@decentnetwork/beagle 0.1.12 → 0.1.13
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/desktop/app.js +93 -6
- package/package.json +1 -1
package/dist/desktop/app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
window.__DK_UI_VERSION="0.1.
|
|
1
|
+
window.__DK_UI_VERSION="0.1.13";
|
|
2
2
|
const ICON_PATHS = {
|
|
3
3
|
// ---- tab bar (the four must feel like one set) ----
|
|
4
4
|
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"/>',
|
|
@@ -1528,6 +1528,72 @@ function dkMarkdownHtml(src) {
|
|
|
1528
1528
|
}
|
|
1529
1529
|
return html || dkHtmlEscape(src);
|
|
1530
1530
|
}
|
|
1531
|
+
const DK_NATIVE_MEDIA_MIME = {
|
|
1532
|
+
".jpg": "image/jpeg",
|
|
1533
|
+
".jpeg": "image/jpeg",
|
|
1534
|
+
".png": "image/png",
|
|
1535
|
+
".gif": "image/gif",
|
|
1536
|
+
".webp": "image/webp",
|
|
1537
|
+
".heic": "image/heic",
|
|
1538
|
+
".m4a": "audio/mp4",
|
|
1539
|
+
".aac": "audio/aac",
|
|
1540
|
+
".mp3": "audio/mpeg",
|
|
1541
|
+
".wav": "audio/wav",
|
|
1542
|
+
".caf": "audio/x-caf",
|
|
1543
|
+
".mp4": "video/mp4",
|
|
1544
|
+
".mov": "video/quicktime",
|
|
1545
|
+
".m4v": "video/x-m4v"
|
|
1546
|
+
};
|
|
1547
|
+
const DK_GROUP_TS_RE = /\n?\[(20\d{2}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{2}:\d{2})\]\s*$/;
|
|
1548
|
+
function dkStripGroupTs(text) {
|
|
1549
|
+
const m = DK_GROUP_TS_RE.exec(text);
|
|
1550
|
+
return m ? { body: text.slice(0, m.index), ts: m[1] } : { body: text, ts: null };
|
|
1551
|
+
}
|
|
1552
|
+
function dkSplitGroupSender(text) {
|
|
1553
|
+
const m = /^([^:\n]{1,48}):\s([\s\S]+)$/.exec(text);
|
|
1554
|
+
return m ? { sender: m[1], body: m[2] } : null;
|
|
1555
|
+
}
|
|
1556
|
+
function dkGroupParse(text) {
|
|
1557
|
+
const t = String(text || "");
|
|
1558
|
+
const { body: noTs, ts } = dkStripGroupTs(t);
|
|
1559
|
+
const split = dkSplitGroupSender(noTs.trim());
|
|
1560
|
+
if (!split)
|
|
1561
|
+
return null;
|
|
1562
|
+
return { sender: split.sender, body: split.body.trim(), ts, strong: !!ts };
|
|
1563
|
+
}
|
|
1564
|
+
function dkThreadIsGroup(thread) {
|
|
1565
|
+
return (thread || []).some((m) => !m.day && m.dir !== "out" && !m.file && (dkGroupParse(m.text) || {}).strong);
|
|
1566
|
+
}
|
|
1567
|
+
function dkNativeMediaFromText(text) {
|
|
1568
|
+
let body = dkStripGroupTs(String(text || "")).body.trim();
|
|
1569
|
+
if (body.length < 32)
|
|
1570
|
+
return null;
|
|
1571
|
+
let sender = null;
|
|
1572
|
+
if (!body.startsWith("{")) {
|
|
1573
|
+
const split = dkSplitGroupSender(body);
|
|
1574
|
+
if (!split || !split.body.startsWith("{"))
|
|
1575
|
+
return null;
|
|
1576
|
+
sender = split.sender;
|
|
1577
|
+
body = split.body.trim();
|
|
1578
|
+
}
|
|
1579
|
+
if (!body.startsWith("{") || !body.endsWith("}"))
|
|
1580
|
+
return null;
|
|
1581
|
+
let j = null;
|
|
1582
|
+
try {
|
|
1583
|
+
j = JSON.parse(body);
|
|
1584
|
+
} catch (e) {
|
|
1585
|
+
return null;
|
|
1586
|
+
}
|
|
1587
|
+
if (!j || typeof j !== "object" || typeof j.data !== "string" || j.data.length < 16)
|
|
1588
|
+
return null;
|
|
1589
|
+
const kind = j.type === "image" ? "image" : j.type === "audio" || j.type === "voice" ? "audio" : j.type === "video" ? "video" : null;
|
|
1590
|
+
if (!kind)
|
|
1591
|
+
return null;
|
|
1592
|
+
const ext = String(j.fileExtension || "").toLowerCase();
|
|
1593
|
+
const mime = DK_NATIVE_MEDIA_MIME[ext] || kind + "/*";
|
|
1594
|
+
const name = String(j.fileName || "file") + ext;
|
|
1595
|
+
return { sender, kind, name, url: "data:" + mime + ";base64," + j.data.replace(/\s+/g, "") };
|
|
1596
|
+
}
|
|
1531
1597
|
function MarkdownText({ text }) {
|
|
1532
1598
|
return /* @__PURE__ */ React.createElement("div", { className: "dk-md", dangerouslySetInnerHTML: { __html: dkMarkdownHtml(text) } });
|
|
1533
1599
|
}
|
|
@@ -1701,9 +1767,11 @@ function DkChatForm({ form, submitted, peer, onSubmit }) {
|
|
|
1701
1767
|
return null;
|
|
1702
1768
|
}), err && /* @__PURE__ */ React.createElement("div", { style: { color: "var(--danger, #ff6b6b)", fontSize: 11.5, fontFamily: "var(--mono)" } }, err));
|
|
1703
1769
|
}
|
|
1704
|
-
function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onCall, onFormSubmit, answered, selMode, selected, onToggleSel, busy }) {
|
|
1770
|
+
function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onCall, onFormSubmit, answered, selMode, selected, onToggleSel, busy, isGroup }) {
|
|
1705
1771
|
const mine = m.from === "me";
|
|
1706
|
-
const
|
|
1772
|
+
const nativeMedia = !m.file ? dkNativeMediaFromText(m.text) : null;
|
|
1773
|
+
const grp = isGroup && m.dir !== "out" && !m.file && !nativeMedia ? dkGroupParse(m.text) : null;
|
|
1774
|
+
const read = window.ChatComponents ? window.ChatComponents.readMessage((grp ? grp.body : m.text) || "") : { text: grp ? grp.body : m.text, form: null, interaction: null };
|
|
1707
1775
|
const submitted = read.form && answered ? answered.get(read.form.custom_id) : null;
|
|
1708
1776
|
const rtcFile = !mine && !m.file ? dkRtcFileFromText(peer.userId || peer.id, m.text) : null;
|
|
1709
1777
|
const callRec = !m.file ? dkCallFromText(m.text) : null;
|
|
@@ -1934,7 +2002,22 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
1934
2002
|
)
|
|
1935
2003
|
);
|
|
1936
2004
|
})()
|
|
1937
|
-
) : /* @__PURE__ */ React.createElement("div", { style: {
|
|
2005
|
+
) : nativeMedia ? /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 4, maxWidth: "min(420px, 88%)" } }, nativeMedia.sender && /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, nativeMedia.sender), nativeMedia.kind === "image" ? /* @__PURE__ */ React.createElement(
|
|
2006
|
+
"img",
|
|
2007
|
+
{
|
|
2008
|
+
src: nativeMedia.url,
|
|
2009
|
+
alt: nativeMedia.name,
|
|
2010
|
+
style: { maxWidth: "100%", borderRadius: 12, border: "1px solid var(--line)", cursor: "pointer" },
|
|
2011
|
+
onClick: () => {
|
|
2012
|
+
try {
|
|
2013
|
+
const w = window.open();
|
|
2014
|
+
if (w)
|
|
2015
|
+
w.document.write('<img src="' + nativeMedia.url + '" style="max-width:100%">');
|
|
2016
|
+
} catch (e) {
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
) : nativeMedia.kind === "audio" ? /* @__PURE__ */ React.createElement("audio", { controls: true, src: nativeMedia.url, style: { maxWidth: "100%" } }) : /* @__PURE__ */ React.createElement("video", { controls: true, src: nativeMedia.url, style: { maxWidth: "100%", borderRadius: 12, border: "1px solid var(--line)" } })) : /* @__PURE__ */ React.createElement(React.Fragment, null, grp && /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)", margin: "0 3px 2px" } }, grp.sender), /* @__PURE__ */ React.createElement("div", { style: {
|
|
1938
2021
|
padding: "8px 12px",
|
|
1939
2022
|
borderRadius: 12,
|
|
1940
2023
|
borderBottomRightRadius: mine ? 4 : 12,
|
|
@@ -1950,7 +2033,7 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
1950
2033
|
lineHeight: 1.4,
|
|
1951
2034
|
letterSpacing: -0.1,
|
|
1952
2035
|
wordBreak: "break-word"
|
|
1953
|
-
} }, /* @__PURE__ */ React.createElement(MarkdownText, { text: read.text })), read.form && /* @__PURE__ */ React.createElement("div", { style: { marginTop: 6 } }, /* @__PURE__ */ React.createElement(DkChatForm, { form: read.form, submitted, peer, onSubmit: onFormSubmit })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 4, margin: "3px 3px 0" } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10, color: "var(--faint)" } }, m.time), !mine && m.via && /* @__PURE__ */ React.createElement(
|
|
2036
|
+
} }, /* @__PURE__ */ React.createElement(MarkdownText, { text: read.text }))), read.form && /* @__PURE__ */ React.createElement("div", { style: { marginTop: 6 } }, /* @__PURE__ */ React.createElement(DkChatForm, { form: read.form, submitted, peer, onSubmit: onFormSubmit })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 4, margin: "3px 3px 0" } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10, color: "var(--faint)" } }, m.time), !mine && m.via && /* @__PURE__ */ React.createElement(
|
|
1954
2037
|
"span",
|
|
1955
2038
|
{
|
|
1956
2039
|
title: m.via === "offline" ? "delivered via express relay (offline)" : "delivered over a live session (online)",
|
|
@@ -1981,6 +2064,7 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
1981
2064
|
}
|
|
1982
2065
|
function Conversation({ T, peer, lang, thread: threadProp, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread }) {
|
|
1983
2066
|
const scrollRef = React.useRef(null);
|
|
2067
|
+
const isGroup = React.useMemo(() => dkThreadIsGroup(threadProp), [threadProp]);
|
|
1984
2068
|
const followScrollRef = React.useRef(true);
|
|
1985
2069
|
const fileRef = React.useRef(null);
|
|
1986
2070
|
const rtcFileRef = React.useRef(null);
|
|
@@ -2233,7 +2317,7 @@ function Conversation({ T, peer, lang, thread: threadProp, onSend, onSendFile, o
|
|
|
2233
2317
|
onDrop
|
|
2234
2318
|
},
|
|
2235
2319
|
dragOver && /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", inset: 0, zIndex: 30, background: "rgba(91,140,255,0.10)", border: "2px dashed var(--accent)", borderRadius: 12, display: "flex", alignItems: "center", justifyContent: "center", pointerEvents: "none", fontFamily: "var(--mono)", fontSize: 14, color: "var(--accent)" } }, lang === "zh" ? "\u677E\u5F00\u53D1\u9001\u6587\u4EF6" : "Drop to send file"),
|
|
2236
|
-
/* @__PURE__ */ React.createElement("div", { style: { height: 60, flexShrink: 0, borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 12, padding: "0 16px", background: "var(--panel)" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: peer.alias ? "var(--ui)" : "var(--mono)", fontSize: 15, fontWeight: 700, color: "var(--text)" } }, peer.alias || shortKey(peer.userId, 10, 6)), peer.agent && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "agent"), /* @__PURE__ */ React.createElement(RouteTag, { peer })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 2 } }, /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.userId, title: peer.userId }, shortKey(peer.userId, 10, 6)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement("button", { onClick: () => onOpenNet(peer), title: T && T.openNet || "Network view", style: { background: "none", border: "none", cursor: "pointer", padding: 0, color: "var(--accent)", display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "network", size: 12, stroke: 2 })), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.ip, title: peer.ip }, peer.ip), peer.address && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement(
|
|
2320
|
+
/* @__PURE__ */ React.createElement("div", { style: { height: 60, flexShrink: 0, borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 12, padding: "0 16px", background: "var(--panel)" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: peer.alias ? "var(--ui)" : "var(--mono)", fontSize: 15, fontWeight: 700, color: "var(--text)" } }, peer.alias || shortKey(peer.userId, 10, 6)), peer.agent && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "agent"), isGroup && /* @__PURE__ */ React.createElement(Tag, null, T && T.groupTag || "group"), /* @__PURE__ */ React.createElement(RouteTag, { peer })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 2 } }, /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.userId, title: peer.userId }, shortKey(peer.userId, 10, 6)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement("button", { onClick: () => onOpenNet(peer), title: T && T.openNet || "Network view", style: { background: "none", border: "none", cursor: "pointer", padding: 0, color: "var(--accent)", display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "network", size: 12, stroke: 2 })), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.ip, title: peer.ip }, peer.ip), peer.address && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement(
|
|
2237
2321
|
Mono,
|
|
2238
2322
|
{
|
|
2239
2323
|
size: 11.5,
|
|
@@ -2283,6 +2367,7 @@ ${peer.address}`
|
|
|
2283
2367
|
m,
|
|
2284
2368
|
peer,
|
|
2285
2369
|
T,
|
|
2370
|
+
isGroup,
|
|
2286
2371
|
onTheater: setTheater,
|
|
2287
2372
|
onDelete: (id) => doDelete([id]),
|
|
2288
2373
|
onCancel: doCancel,
|
|
@@ -3493,6 +3578,7 @@ const STR = {
|
|
|
3493
3578
|
pickPeer: "Select a peer to open the conversation",
|
|
3494
3579
|
queued: "queued",
|
|
3495
3580
|
sendingMsg: "sending",
|
|
3581
|
+
groupTag: "group",
|
|
3496
3582
|
open: "open",
|
|
3497
3583
|
retry: "Retry",
|
|
3498
3584
|
cancel: "Cancel",
|
|
@@ -3589,6 +3675,7 @@ const STR = {
|
|
|
3589
3675
|
pickPeer: "\u9009\u62E9\u4E00\u4F4D\u597D\u53CB\u5F00\u59CB\u4F1A\u8BDD",
|
|
3590
3676
|
queued: "\u5F85\u53D1\u9001",
|
|
3591
3677
|
sendingMsg: "\u53D1\u9001\u4E2D",
|
|
3678
|
+
groupTag: "\u7FA4",
|
|
3592
3679
|
open: "\u6253\u5F00",
|
|
3593
3680
|
retry: "\u91CD\u8BD5",
|
|
3594
3681
|
cancel: "\u53D6\u6D88",
|
package/package.json
CHANGED