@decentnetwork/beagle-ui 0.2.7 → 0.2.8
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 +237 -7
- package/package.json +1 -1
package/dist/beagle-ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const BEAGLE_UI_VERSION = "0.2.
|
|
1
|
+
export const BEAGLE_UI_VERSION = "0.2.7";
|
|
2
2
|
// src/icons.jsx
|
|
3
3
|
var ICON_PATHS = {
|
|
4
4
|
// ---- tab bar (the four must feel like one set) ----
|
|
@@ -527,6 +527,9 @@ function PeerRow({ peer, T, active, onClick }) {
|
|
|
527
527
|
minWidth: 0
|
|
528
528
|
} }, dkContactPreview(peer.lastMsg) || peer.lastMsg))), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 4, flexShrink: 0 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, peer.lastTime), peer.unread ? /* @__PURE__ */ React.createElement(Unread, { n: peer.unread }) : peer.pending ? /* @__PURE__ */ React.createElement(Icon, { name: "clock", size: 11, stroke: 2.2, color: "var(--warn, #d29922)", title: "friend request pending" }) : /* @__PURE__ */ React.createElement(StatusDot, { online: peer.online })));
|
|
529
529
|
}
|
|
530
|
+
function dkActivityTs(p) {
|
|
531
|
+
return Math.max(p.lastTs || 0, p.acceptedAt || 0, p.requestedAt || 0);
|
|
532
|
+
}
|
|
530
533
|
function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed }) {
|
|
531
534
|
const [q, setQ] = React.useState("");
|
|
532
535
|
const [addr, setAddr] = React.useState("");
|
|
@@ -564,7 +567,7 @@ function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, pre
|
|
|
564
567
|
const s = (p.alias || "") + " " + p.userId + " " + p.ip;
|
|
565
568
|
return s.toLowerCase().includes(q.toLowerCase());
|
|
566
569
|
}).slice().sort((a, b) => {
|
|
567
|
-
const ta = a
|
|
570
|
+
const ta = dkActivityTs(a), tb = dkActivityTs(b);
|
|
568
571
|
if (ta !== tb)
|
|
569
572
|
return tb - ta;
|
|
570
573
|
return String(a.alias || a.userId || "").localeCompare(String(b.alias || b.userId || ""));
|
|
@@ -2725,6 +2728,35 @@ function DkDisplaySettings({ t, setTweak }) {
|
|
|
2725
2728
|
)));
|
|
2726
2729
|
return /* @__PURE__ */ React.createElement(Card, { label: zh ? "\u663E\u793A" : "Display" }, /* @__PURE__ */ React.createElement("div", { style: { ...row, borderBottom: "1px solid var(--line)" } }, /* @__PURE__ */ React.createElement("span", { style: name }, zh ? "\u8BED\u8A00" : "Language"), seg("lang", t.lang, (v) => setTweak("lang", v), [["en", "EN"], ["zh", "\u4E2D\u6587"]])), /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: name }, zh ? "\u4E3B\u9898" : "Theme"), seg("theme", t.theme, (v) => setTweak("theme", v), [["dark", zh ? "\u6DF1\u8272" : "Dark"], ["light", zh ? "\u6D45\u8272" : "Light"]])));
|
|
2727
2730
|
}
|
|
2731
|
+
function DkAlertSettings({ t, setTweak }) {
|
|
2732
|
+
const zh = t.lang === "zh";
|
|
2733
|
+
const toggle = (key, label, sub, last) => /* @__PURE__ */ React.createElement("label", { style: {
|
|
2734
|
+
display: "flex",
|
|
2735
|
+
alignItems: "center",
|
|
2736
|
+
gap: 13,
|
|
2737
|
+
padding: "13px 16px",
|
|
2738
|
+
cursor: "pointer",
|
|
2739
|
+
borderBottom: last ? "none" : "1px solid var(--line)"
|
|
2740
|
+
} }, /* @__PURE__ */ React.createElement(
|
|
2741
|
+
"input",
|
|
2742
|
+
{
|
|
2743
|
+
type: "checkbox",
|
|
2744
|
+
checked: t[key] !== false,
|
|
2745
|
+
onChange: (e) => setTweak(key, e.target.checked),
|
|
2746
|
+
style: { width: 16, height: 16, accentColor: "var(--accent)" }
|
|
2747
|
+
}
|
|
2748
|
+
), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--text)" } }, label), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)", marginTop: 2 } }, sub)));
|
|
2749
|
+
return /* @__PURE__ */ React.createElement(Card, { label: zh ? "\u63D0\u9192" : "Alerts" }, toggle(
|
|
2750
|
+
"alertSound",
|
|
2751
|
+
zh ? "\u65B0\u6D88\u606F\u63D0\u793A\u97F3" : "Sound for new messages",
|
|
2752
|
+
zh ? "\u6536\u5230\u65B0\u6D88\u606F\u6216\u597D\u53CB\u8BF7\u6C42\u65F6\u64AD\u653E\u77ED\u4FC3\u63D0\u793A\u97F3\u3002\u6B63\u5728\u770B\u7684\u5F53\u524D\u4F1A\u8BDD\u4E0D\u4F1A\u54CD\u3002" : "A short chime when a message or friend request arrives. Silent for the conversation you are reading."
|
|
2753
|
+
), toggle(
|
|
2754
|
+
"alertFlash",
|
|
2755
|
+
zh ? "\u6807\u7B7E\u9875\u95EA\u70C1" : "Flash the tab",
|
|
2756
|
+
zh ? "\u7A97\u53E3\u4E0D\u5728\u524D\u53F0\u65F6\uFF0C\u6807\u7B7E\u6807\u9898\u548C\u56FE\u6807\u95EA\u70C1\u63D0\u793A\uFF0C\u56DE\u5230\u7A97\u53E3\u5373\u505C\u6B62\u3002" : "While this window is in the background, the tab title and icon blink until you come back.",
|
|
2757
|
+
true
|
|
2758
|
+
));
|
|
2759
|
+
}
|
|
2728
2760
|
function ProfileTab({ T, me, onEdit, t, setTweak }) {
|
|
2729
2761
|
var _a;
|
|
2730
2762
|
const [qr, setQr] = React.useState(null);
|
|
@@ -2746,7 +2778,7 @@ function ProfileTab({ T, me, onEdit, t, setTweak }) {
|
|
|
2746
2778
|
},
|
|
2747
2779
|
style: { width: 16, height: 16, accentColor: "var(--accent)" }
|
|
2748
2780
|
}
|
|
2749
|
-
), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--text)" } }, T && T.autoAcceptLabel || "Auto-accept friend requests"), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)", marginTop: 2 } }, T && T.autoAcceptSub || "Off: requests wait in the sidebar for your approval.")))), hostHasKeyBackup && /* @__PURE__ */ React.createElement(DkKeyBackup, { t: t || {} }), t && setTweak && /* @__PURE__ */ React.createElement(DkDisplaySettings, { t, setTweak }), /* @__PURE__ */ React.createElement(Card, { label: T.network }, /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.virtualIp, value: me.ip, copy: true }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.wireLabel, value: `${me.wire} \xB7 lossless`, mono: false }), /* @__PURE__ */ React.createElement(DkVersionRow, { T, me }), /* @__PURE__ */ React.createElement(DkUpdateCheck, { T })), /* @__PURE__ */ React.createElement(Card, { label: T.dangerZone }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 13, padding: "14px 16px" } }, /* @__PURE__ */ React.createElement("div", { style: { width: 34, height: 34, borderRadius: 8, flexShrink: 0, background: "color-mix(in oklab, var(--danger), transparent 86%)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--danger)" } }, /* @__PURE__ */ React.createElement(Icon, { name: "trash", size: 17, stroke: 2 })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--danger)" } }, T.deleteNode), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--faint)", marginTop: 1 } }, T.deleteSub)), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", size: "sm" }, T.delete)))), qr && /* @__PURE__ */ React.createElement(DkQrModal, { T, value: qr.value, label: qr.label, onClose: () => setQr(null) }), editing && /* @__PURE__ */ React.createElement(DkEditModal, { T, me, onClose: () => setEditing(false), onSave: (name, description) => {
|
|
2781
|
+
), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--text)" } }, T && T.autoAcceptLabel || "Auto-accept friend requests"), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)", marginTop: 2 } }, T && T.autoAcceptSub || "Off: requests wait in the sidebar for your approval.")))), hostHasKeyBackup && /* @__PURE__ */ React.createElement(DkKeyBackup, { t: t || {} }), t && setTweak && /* @__PURE__ */ React.createElement(DkAlertSettings, { t, setTweak }), t && setTweak && /* @__PURE__ */ React.createElement(DkDisplaySettings, { t, setTweak }), /* @__PURE__ */ React.createElement(Card, { label: T.network }, /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.virtualIp, value: me.ip, copy: true }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.wireLabel, value: `${me.wire} \xB7 lossless`, mono: false }), /* @__PURE__ */ React.createElement(DkVersionRow, { T, me }), /* @__PURE__ */ React.createElement(DkUpdateCheck, { T })), /* @__PURE__ */ React.createElement(Card, { label: T.dangerZone }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 13, padding: "14px 16px" } }, /* @__PURE__ */ React.createElement("div", { style: { width: 34, height: 34, borderRadius: 8, flexShrink: 0, background: "color-mix(in oklab, var(--danger), transparent 86%)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--danger)" } }, /* @__PURE__ */ React.createElement(Icon, { name: "trash", size: 17, stroke: 2 })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 600, color: "var(--danger)" } }, T.deleteNode), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--faint)", marginTop: 1 } }, T.deleteSub)), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", size: "sm" }, T.delete)))), qr && /* @__PURE__ */ React.createElement(DkQrModal, { T, value: qr.value, label: qr.label, onClose: () => setQr(null) }), editing && /* @__PURE__ */ React.createElement(DkEditModal, { T, me, onClose: () => setEditing(false), onSave: (name, description) => {
|
|
2750
2782
|
if (onEdit)
|
|
2751
2783
|
onEdit(name, description);
|
|
2752
2784
|
setEditing(false);
|
|
@@ -4310,6 +4342,183 @@ function NetworkTab({ T, me, peers, exits, activeExit, reqCount, onSetExit, onOp
|
|
|
4310
4342
|
}
|
|
4311
4343
|
Object.assign(window, { NetworkTab });
|
|
4312
4344
|
|
|
4345
|
+
// src/notify.jsx
|
|
4346
|
+
var dkAudioCtx = null;
|
|
4347
|
+
function dkAudio() {
|
|
4348
|
+
if (dkAudioCtx && dkAudioCtx.state !== "closed")
|
|
4349
|
+
return dkAudioCtx;
|
|
4350
|
+
try {
|
|
4351
|
+
dkAudioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
4352
|
+
} catch (e) {
|
|
4353
|
+
dkAudioCtx = null;
|
|
4354
|
+
}
|
|
4355
|
+
return dkAudioCtx;
|
|
4356
|
+
}
|
|
4357
|
+
function dkUnlockAudioOnGesture() {
|
|
4358
|
+
const unlock = () => {
|
|
4359
|
+
const c = dkAudio();
|
|
4360
|
+
if (c && c.state === "suspended")
|
|
4361
|
+
c.resume().catch(() => {
|
|
4362
|
+
});
|
|
4363
|
+
};
|
|
4364
|
+
window.addEventListener("pointerdown", unlock, { passive: true });
|
|
4365
|
+
window.addEventListener("keydown", unlock, { passive: true });
|
|
4366
|
+
return () => {
|
|
4367
|
+
window.removeEventListener("pointerdown", unlock);
|
|
4368
|
+
window.removeEventListener("keydown", unlock);
|
|
4369
|
+
};
|
|
4370
|
+
}
|
|
4371
|
+
function dkChime(kind) {
|
|
4372
|
+
const c = dkAudio();
|
|
4373
|
+
if (!c)
|
|
4374
|
+
return;
|
|
4375
|
+
if (c.state === "suspended")
|
|
4376
|
+
c.resume().catch(() => {
|
|
4377
|
+
});
|
|
4378
|
+
const notes = kind === "request" ? [[660, 0], [880, 0.14]] : [[880, 0], [1175, 0.11]];
|
|
4379
|
+
const t0 = c.currentTime;
|
|
4380
|
+
for (const [freq, at] of notes) {
|
|
4381
|
+
const o = c.createOscillator(), g = c.createGain();
|
|
4382
|
+
o.type = "sine";
|
|
4383
|
+
o.frequency.value = freq;
|
|
4384
|
+
o.connect(g);
|
|
4385
|
+
g.connect(c.destination);
|
|
4386
|
+
const t = t0 + at;
|
|
4387
|
+
g.gain.setValueAtTime(1e-4, t);
|
|
4388
|
+
g.gain.exponentialRampToValueAtTime(0.18, t + 0.015);
|
|
4389
|
+
g.gain.exponentialRampToValueAtTime(1e-4, t + 0.17);
|
|
4390
|
+
o.start(t);
|
|
4391
|
+
o.stop(t + 0.2);
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
var dkFlash = { timer: null, title: "", link: null, href: null, badged: null, on: false, n: 0, label: "" };
|
|
4395
|
+
function dkBadgedIcon(href) {
|
|
4396
|
+
return new Promise((res, rej) => {
|
|
4397
|
+
const img = new Image();
|
|
4398
|
+
img.onload = () => {
|
|
4399
|
+
try {
|
|
4400
|
+
if (!img.naturalWidth)
|
|
4401
|
+
return rej(new Error("icon has no intrinsic size"));
|
|
4402
|
+
const s = 64, cv = document.createElement("canvas");
|
|
4403
|
+
cv.width = s;
|
|
4404
|
+
cv.height = s;
|
|
4405
|
+
const cx = cv.getContext("2d");
|
|
4406
|
+
cx.drawImage(img, 0, 0, s, s);
|
|
4407
|
+
cx.beginPath();
|
|
4408
|
+
cx.arc(s - 14, 14, 12, 0, Math.PI * 2);
|
|
4409
|
+
cx.fillStyle = "#e5484d";
|
|
4410
|
+
cx.fill();
|
|
4411
|
+
cx.lineWidth = 3;
|
|
4412
|
+
cx.strokeStyle = "#fff";
|
|
4413
|
+
cx.stroke();
|
|
4414
|
+
res(cv.toDataURL("image/png"));
|
|
4415
|
+
} catch (e) {
|
|
4416
|
+
rej(e);
|
|
4417
|
+
}
|
|
4418
|
+
};
|
|
4419
|
+
img.onerror = () => rej(new Error("icon failed to load"));
|
|
4420
|
+
img.src = href;
|
|
4421
|
+
});
|
|
4422
|
+
}
|
|
4423
|
+
function dkFlashTick() {
|
|
4424
|
+
dkFlash.on = !dkFlash.on;
|
|
4425
|
+
document.title = `(${dkFlash.n}) ${dkFlash.on ? dkFlash.label : dkFlash.title}`;
|
|
4426
|
+
}
|
|
4427
|
+
function dkFlashStart(label, count) {
|
|
4428
|
+
dkFlash.n += count || 1;
|
|
4429
|
+
dkFlash.label = label;
|
|
4430
|
+
if (dkFlash.timer)
|
|
4431
|
+
return;
|
|
4432
|
+
dkFlash.title = document.title;
|
|
4433
|
+
dkFlash.link = document.querySelector('link[rel~="icon"]');
|
|
4434
|
+
dkFlash.href = dkFlash.link ? dkFlash.link.href : null;
|
|
4435
|
+
dkFlash.badged = null;
|
|
4436
|
+
dkFlash.on = false;
|
|
4437
|
+
if (dkFlash.href) {
|
|
4438
|
+
dkBadgedIcon(dkFlash.href).then((b) => {
|
|
4439
|
+
dkFlash.badged = b;
|
|
4440
|
+
if (dkFlash.timer && dkFlash.link)
|
|
4441
|
+
dkFlash.link.href = b;
|
|
4442
|
+
}).catch(() => {
|
|
4443
|
+
});
|
|
4444
|
+
}
|
|
4445
|
+
dkFlashTick();
|
|
4446
|
+
dkFlash.timer = setInterval(dkFlashTick, 1e3);
|
|
4447
|
+
}
|
|
4448
|
+
function dkFlashStop() {
|
|
4449
|
+
if (!dkFlash.timer)
|
|
4450
|
+
return;
|
|
4451
|
+
clearInterval(dkFlash.timer);
|
|
4452
|
+
dkFlash.timer = null;
|
|
4453
|
+
dkFlash.n = 0;
|
|
4454
|
+
document.title = dkFlash.title;
|
|
4455
|
+
if (dkFlash.link && dkFlash.href)
|
|
4456
|
+
dkFlash.link.href = dkFlash.href;
|
|
4457
|
+
}
|
|
4458
|
+
function dkLooking() {
|
|
4459
|
+
return document.visibilityState === "visible" && document.hasFocus();
|
|
4460
|
+
}
|
|
4461
|
+
function useIncomingAlerts({ T, peers, requests, loaded, activeId, sound = true, flash = true }) {
|
|
4462
|
+
const prev = React.useRef(null);
|
|
4463
|
+
React.useEffect(() => dkUnlockAudioOnGesture(), []);
|
|
4464
|
+
React.useEffect(() => {
|
|
4465
|
+
if (!flash)
|
|
4466
|
+
dkFlashStop();
|
|
4467
|
+
}, [flash]);
|
|
4468
|
+
React.useEffect(() => {
|
|
4469
|
+
const seen = () => {
|
|
4470
|
+
if (dkLooking())
|
|
4471
|
+
dkFlashStop();
|
|
4472
|
+
};
|
|
4473
|
+
window.addEventListener("focus", seen);
|
|
4474
|
+
window.addEventListener("pointerdown", seen, { passive: true });
|
|
4475
|
+
document.addEventListener("visibilitychange", seen);
|
|
4476
|
+
return () => {
|
|
4477
|
+
window.removeEventListener("focus", seen);
|
|
4478
|
+
window.removeEventListener("pointerdown", seen);
|
|
4479
|
+
document.removeEventListener("visibilitychange", seen);
|
|
4480
|
+
dkFlashStop();
|
|
4481
|
+
};
|
|
4482
|
+
}, []);
|
|
4483
|
+
React.useEffect(() => {
|
|
4484
|
+
if (!loaded)
|
|
4485
|
+
return;
|
|
4486
|
+
const byId = /* @__PURE__ */ new Map();
|
|
4487
|
+
for (const p of peers || []) {
|
|
4488
|
+
const dir = p.lastDir || (String(p.lastMsg || "").startsWith("you: ") ? "out" : "in");
|
|
4489
|
+
byId.set(p.id, { ts: p.lastTs || 0, dir });
|
|
4490
|
+
}
|
|
4491
|
+
const reqIds = new Set((requests || []).map((r) => r.id));
|
|
4492
|
+
const was = prev.current;
|
|
4493
|
+
prev.current = { byId, reqIds };
|
|
4494
|
+
if (!was)
|
|
4495
|
+
return;
|
|
4496
|
+
let msgs = 0, elsewhere = 0, reqs = 0;
|
|
4497
|
+
for (const [id, cur] of byId) {
|
|
4498
|
+
if (cur.dir !== "in" || !cur.ts)
|
|
4499
|
+
continue;
|
|
4500
|
+
const old = was.byId.get(id);
|
|
4501
|
+
if (old ? cur.ts <= old.ts : Date.now() - cur.ts > 3e4)
|
|
4502
|
+
continue;
|
|
4503
|
+
msgs += 1;
|
|
4504
|
+
if (id !== activeId)
|
|
4505
|
+
elsewhere += 1;
|
|
4506
|
+
}
|
|
4507
|
+
for (const id of reqIds)
|
|
4508
|
+
if (!was.reqIds.has(id))
|
|
4509
|
+
reqs += 1;
|
|
4510
|
+
if (!msgs && !reqs)
|
|
4511
|
+
return;
|
|
4512
|
+
const looking = dkLooking();
|
|
4513
|
+
if (sound && !(looking && !reqs && !elsewhere))
|
|
4514
|
+
dkChime(reqs && !msgs ? "request" : "message");
|
|
4515
|
+
if (flash && !looking) {
|
|
4516
|
+
const label = msgs ? T && T.alertMsg || "New message" : T && T.alertReq || "New friend request";
|
|
4517
|
+
dkFlashStart(label, msgs + reqs);
|
|
4518
|
+
}
|
|
4519
|
+
}, [peers, requests, loaded, activeId, T, sound, flash]);
|
|
4520
|
+
}
|
|
4521
|
+
|
|
4313
4522
|
// src/settings-store.jsx
|
|
4314
4523
|
var TWEAKS_STORAGE_KEY = "decentlan.tweaks";
|
|
4315
4524
|
function useTweaks(defaults) {
|
|
@@ -4370,7 +4579,9 @@ var DK_DEFAULTS = (
|
|
|
4370
4579
|
"accent": "#7B6CF6",
|
|
4371
4580
|
"density": "compact",
|
|
4372
4581
|
"lang": "en",
|
|
4373
|
-
"startTab": "chat"
|
|
4582
|
+
"startTab": "chat",
|
|
4583
|
+
"alertSound": true,
|
|
4584
|
+
"alertFlash": true
|
|
4374
4585
|
}
|
|
4375
4586
|
);
|
|
4376
4587
|
function dkDetectLang() {
|
|
@@ -4439,6 +4650,8 @@ var STR = {
|
|
|
4439
4650
|
network: "Network",
|
|
4440
4651
|
apps: "Apps",
|
|
4441
4652
|
profile: "Profile",
|
|
4653
|
+
alertMsg: "New message",
|
|
4654
|
+
alertReq: "New friend request",
|
|
4442
4655
|
recommended: "Discover",
|
|
4443
4656
|
registered: "Names",
|
|
4444
4657
|
here: "Here",
|
|
@@ -4619,6 +4832,8 @@ var STR = {
|
|
|
4619
4832
|
network: "\u7F51\u7EDC",
|
|
4620
4833
|
apps: "\u5E94\u7528",
|
|
4621
4834
|
profile: "\u6211\u7684",
|
|
4835
|
+
alertMsg: "\u65B0\u6D88\u606F",
|
|
4836
|
+
alertReq: "\u65B0\u7684\u597D\u53CB\u8BF7\u6C42",
|
|
4622
4837
|
recommended: "\u63A8\u8350",
|
|
4623
4838
|
registered: "\u540D\u5F55",
|
|
4624
4839
|
here: "\u5728\u573A",
|
|
@@ -5011,6 +5226,15 @@ function DkApp() {
|
|
|
5011
5226
|
const T = STR[t.lang] || STR.en;
|
|
5012
5227
|
const vars = dkTheme(t.theme, t.accent);
|
|
5013
5228
|
const rowPad = t.density === "comfortable" ? "11px 12px" : "7px 10px";
|
|
5229
|
+
useIncomingAlerts({
|
|
5230
|
+
T,
|
|
5231
|
+
peers,
|
|
5232
|
+
requests,
|
|
5233
|
+
loaded: data.loaded,
|
|
5234
|
+
activeId,
|
|
5235
|
+
sound: t.alertSound !== false,
|
|
5236
|
+
flash: t.alertFlash !== false
|
|
5237
|
+
});
|
|
5014
5238
|
const callCtl = useCallController(me.userId, (peerId, video, direction) => {
|
|
5015
5239
|
const text = `WebRTC ${video ? "video" : "audio"} call: ${direction}`;
|
|
5016
5240
|
dkApi.logLocal(peerId, direction === "outgoing" ? "out" : "in", text).then(() => {
|
|
@@ -5152,10 +5376,16 @@ function DkApp() {
|
|
|
5152
5376
|
{ id: "recommended", icon: "sparkles", label: T.recommended },
|
|
5153
5377
|
{ id: "registered", icon: "at", label: T.registered },
|
|
5154
5378
|
{ id: "network", icon: "network", label: T.network },
|
|
5155
|
-
{ id: "apps", icon: "grid", label: T.apps }
|
|
5156
|
-
{ id: "profile", icon: "userRound", label: T.profile }
|
|
5379
|
+
{ id: "apps", icon: "grid", label: T.apps }
|
|
5157
5380
|
];
|
|
5158
|
-
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("
|
|
5381
|
+
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("button", { onClick: () => setTab("profile"), title: T.profile, style: {
|
|
5382
|
+
padding: 4,
|
|
5383
|
+
borderRadius: 12,
|
|
5384
|
+
cursor: "pointer",
|
|
5385
|
+
display: "flex",
|
|
5386
|
+
border: "1px solid " + (tab === "profile" ? "var(--line)" : "transparent"),
|
|
5387
|
+
background: tab === "profile" ? "var(--panel-2)" : "transparent"
|
|
5388
|
+
} }, /* @__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: T.profile }).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(
|
|
5159
5389
|
DkLockedOut,
|
|
5160
5390
|
{
|
|
5161
5391
|
compact: true,
|
package/package.json
CHANGED