@decentnetwork/beagle-ui 0.2.35 → 0.2.36

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.
Files changed (2) hide show
  1. package/dist/beagle-ui.js +120 -7
  2. package/package.json +1 -1
package/dist/beagle-ui.js CHANGED
@@ -1,4 +1,4 @@
1
- export const BEAGLE_UI_VERSION = "0.2.35";
1
+ export const BEAGLE_UI_VERSION = "0.2.36";
2
2
  // src/icons.jsx
3
3
  var ICON_PATHS = {
4
4
  // ---- tab bar (the four must feel like one set) ----
@@ -276,7 +276,7 @@ function collapseProtocol(thread, isProto, lang) {
276
276
  };
277
277
  (thread || []).forEach((m, i) => {
278
278
  const hit = m && !m.day ? isProto({ text: m.text, dir: m && m.from === "me" ? "out" : "in", ts: m && m.ts }) : false;
279
- if (!hit || m && m.file) {
279
+ if (!hit || m && (m.file || m.kind === "friend-request")) {
280
280
  flush();
281
281
  out.push(m);
282
282
  return;
@@ -535,7 +535,10 @@ function dkThreadMsg(m) {
535
535
  // Brief 30: a validated component form, already whitelisted host-side.
536
536
  // Passed through untouched — the renderer treats every string as text,
537
537
  // never markup.
538
- components: m.components
538
+ components: m.components,
539
+ // 'friend-request': the accepted request's greeting, merged in by the
540
+ // host (beagle's friend-greetings.ts); chat.jsx draws its own bubble.
541
+ kind: m.kind
539
542
  };
540
543
  }
541
544
  var DK_TAIL_MIN = 30;
@@ -632,8 +635,16 @@ function useDaemonData() {
632
635
  if (!c)
633
636
  return;
634
637
  const arr = [...c.byId.values()].sort((a, b) => a.ts - b.ts);
635
- const msgs = arr.map(dkThreadMsg);
636
- const withDay = msgs.length ? [{ day: dkDayLabel(arr[0].ts) }].concat(msgs) : [];
638
+ const withDay = [];
639
+ let lastDay = null;
640
+ for (const m of arr) {
641
+ const day = dkDayLabel(m.ts);
642
+ if (day !== lastDay) {
643
+ withDay.push({ day });
644
+ lastDay = day;
645
+ }
646
+ withDay.push(dkThreadMsg(m));
647
+ }
637
648
  setThreads((t) => Object.assign({}, t, { [peerId]: withDay }));
638
649
  setEarlier((e) => e[peerId] === c.more ? e : Object.assign({}, e, { [peerId]: c.more }));
639
650
  }, []);
@@ -1745,6 +1756,27 @@ function requestAvatarSource(r, skipUrl = false) {
1745
1756
  return { kind: "ens" };
1746
1757
  }
1747
1758
 
1759
+ // src/request-greeting.js
1760
+ var REQUEST_TRANSPORTS = ["lan", "carrier", "direct", "relay", "express", "webrtc", "online", "offline", "tcp", "udp", "p2p"];
1761
+ function unquote(s) {
1762
+ const m = /^"([\s\S]*)"$/.exec(s);
1763
+ return m ? m[1] : s;
1764
+ }
1765
+ function requestGreeting(r) {
1766
+ const hello = r && typeof r.hello === "string" ? r.hello.trim() : "";
1767
+ const via = r && typeof r.via === "string" ? r.via.trim() : "";
1768
+ const isTransport = !!via && REQUEST_TRANSPORTS.includes(via.toLowerCase());
1769
+ const isName = !!via && !!r && typeof r.name === "string" && r.name.trim() === via;
1770
+ return {
1771
+ greeting: hello || (via && !isTransport && !isName ? unquote(via).trim() : ""),
1772
+ transport: isTransport ? via : ""
1773
+ };
1774
+ }
1775
+ var GREETING_KIND = "friend-request";
1776
+ function isGreetingItem(m) {
1777
+ return !!m && m.kind === GREETING_KIND;
1778
+ }
1779
+
1748
1780
  // src/chat.jsx
1749
1781
  var DK_CMD_HIST_KEY = "beagle.assistant.history";
1750
1782
  var DK_CMD_HIST_MAX = 50;
@@ -1797,7 +1829,7 @@ function RequestsBlock({ T, requests, onAct }) {
1797
1829
  overflow: "hidden",
1798
1830
  textOverflow: "ellipsis",
1799
1831
  whiteSpace: "nowrap"
1800
- } }, r.name) : /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--faint)", fontStyle: "italic" } }, T.noName || "no name given"), /* @__PURE__ */ React.createElement(Mono, { size: 11, copy: r.carrier, title: r.carrier }, shortKey(r.carrier, 8, 6)), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)", marginTop: 2 } }, "via ", r.via, " \xB7 ", r.time))), r.descr && /* @__PURE__ */ React.createElement("div", { style: {
1832
+ } }, r.name) : /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--faint)", fontStyle: "italic" } }, T.noName || "no name given"), /* @__PURE__ */ React.createElement(Mono, { size: 11, copy: r.carrier, title: r.carrier }, shortKey(r.carrier, 8, 6)), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)", marginTop: 2 } }, requestGreeting(r).transport ? "via " + requestGreeting(r).transport + " \xB7 " : "", r.time))), /* @__PURE__ */ React.createElement(DkRequestGreeting, { T, text: requestGreeting(r).greeting }), r.descr && /* @__PURE__ */ React.createElement("div", { style: {
1801
1833
  fontFamily: "var(--ui)",
1802
1834
  fontSize: 12,
1803
1835
  color: "var(--dim, var(--faint))",
@@ -1806,6 +1838,76 @@ function RequestsBlock({ T, requests, onAct }) {
1806
1838
  paddingLeft: 8
1807
1839
  } }, r.descr), failed[r.id] && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11, color: "var(--danger)" } }, failed[r.id]), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 6 } }, /* @__PURE__ */ React.createElement(Btn, { tone: "ok", icon: "check", size: "sm", onClick: () => act(r, "accept"), style: { flex: 1 } }, T.accept), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", icon: "x", size: "sm", onClick: () => act(r, "reject"), style: { flex: 1 } }, T.reject))))));
1808
1840
  }
1841
+ function DkRequestGreeting({ T, text }) {
1842
+ const [open, setOpen] = React.useState(false);
1843
+ const [clipped, setClipped] = React.useState(false);
1844
+ const ref = React.useRef(null);
1845
+ React.useLayoutEffect(() => {
1846
+ const el = ref.current;
1847
+ if (el && !open)
1848
+ setClipped(el.scrollHeight > el.clientHeight + 1);
1849
+ }, [text, open]);
1850
+ if (!text)
1851
+ return null;
1852
+ const toggle = () => {
1853
+ try {
1854
+ const sel = window.getSelection && window.getSelection();
1855
+ if (sel && String(sel).length)
1856
+ return;
1857
+ } catch (e) {
1858
+ }
1859
+ if (clipped || open)
1860
+ setOpen((o) => !o);
1861
+ };
1862
+ return /* @__PURE__ */ React.createElement(
1863
+ "div",
1864
+ {
1865
+ onClick: toggle,
1866
+ title: !open && clipped ? T.showAll || "show all" : void 0,
1867
+ style: { cursor: clipped || open ? "pointer" : "text" }
1868
+ },
1869
+ /* @__PURE__ */ React.createElement("div", { style: { background: "var(--bub-them)", border: "1px solid var(--line)", borderRadius: 8, padding: "6px 9px" } }, /* @__PURE__ */ React.createElement("div", { ref, style: {
1870
+ fontFamily: "var(--ui)",
1871
+ fontSize: 12.5,
1872
+ color: "var(--text)",
1873
+ lineHeight: 1.45,
1874
+ whiteSpace: "pre-wrap",
1875
+ overflowWrap: "anywhere",
1876
+ userSelect: "text",
1877
+ WebkitUserSelect: "text",
1878
+ ...open ? { maxHeight: 240, overflowY: "auto" } : { display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }
1879
+ } }, text)),
1880
+ (clipped || open) && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11, color: "var(--accent)", marginTop: 3 } }, open ? T.showLess || "show less" : T.showAll || "show all")
1881
+ );
1882
+ }
1883
+ function DkGreetingMsg({ m, peer, T }) {
1884
+ return /* @__PURE__ */ React.createElement("div", { style: { display: "flex", justifyContent: "flex-start", alignItems: "flex-end", gap: 8, margin: "3px 0 10px" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 24, radius: 6, dot: false }), /* @__PURE__ */ React.createElement("div", { style: {
1885
+ maxWidth: "75%",
1886
+ padding: "8px 12px",
1887
+ borderRadius: 12,
1888
+ borderBottomLeftRadius: 4,
1889
+ background: "var(--panel-2)",
1890
+ border: "1px dashed var(--accent)",
1891
+ color: "var(--text)"
1892
+ } }, /* @__PURE__ */ React.createElement("div", { style: {
1893
+ display: "flex",
1894
+ alignItems: "center",
1895
+ gap: 6,
1896
+ marginBottom: 4,
1897
+ fontFamily: "var(--mono)",
1898
+ fontSize: 10.5,
1899
+ color: "var(--accent)",
1900
+ fontWeight: 600
1901
+ } }, /* @__PURE__ */ React.createElement(Icon, { name: "userPlus", size: 12, stroke: 2.2, color: "var(--accent)" }), /* @__PURE__ */ React.createElement("span", null, T.friendRequestItem || "Friend request"), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--faint)", fontWeight: 400 } }, "\xB7 ", m.time)), /* @__PURE__ */ React.createElement("div", { style: {
1902
+ fontFamily: "var(--ui)",
1903
+ fontSize: 13.5,
1904
+ lineHeight: 1.5,
1905
+ whiteSpace: "pre-wrap",
1906
+ overflowWrap: "anywhere",
1907
+ userSelect: "text",
1908
+ WebkitUserSelect: "text"
1909
+ } }, m.text)));
1910
+ }
1809
1911
  function DkRequestAvatar({ r, size, radius }) {
1810
1912
  const [urlBroken, setUrlBroken] = React.useState(false);
1811
1913
  const url = requestAvatarUrl(r);
@@ -2580,7 +2682,12 @@ function DkChatForm({ form, submitted, peer, onSubmit }) {
2580
2682
  return null;
2581
2683
  }), err && /* @__PURE__ */ React.createElement("div", { style: { color: "var(--danger, #ff6b6b)", fontSize: 11.5, fontFamily: "var(--mono)" } }, err));
2582
2684
  }
2583
- function Msg({ m, peer, T, lang, onTheater, onDelete, onCancel, onRetry, onRetryMsg, onReveal, onOpenFile, onCall, onFormSubmit, onNameCard, onAssistantRemove, onAssistantAdopt, answered, selMode, selected, onToggleSel, busy, isGroup }) {
2685
+ function Msg(props) {
2686
+ if (isGreetingItem(props.m))
2687
+ return /* @__PURE__ */ React.createElement(DkGreetingMsg, { m: props.m, peer: props.peer, T: props.T });
2688
+ return /* @__PURE__ */ React.createElement(DkMsgBody, { ...props });
2689
+ }
2690
+ function DkMsgBody({ m, peer, T, lang, onTheater, onDelete, onCancel, onRetry, onRetryMsg, onReveal, onOpenFile, onCall, onFormSubmit, onNameCard, onAssistantRemove, onAssistantAdopt, answered, selMode, selected, onToggleSel, busy, isGroup }) {
2584
2691
  const mine = m.from === "me";
2585
2692
  const nativeMedia = !m.file ? dkNativeMediaFromText(m.text) : null;
2586
2693
  const grp = isGroup && m.dir !== "out" && !m.file && !nativeMedia ? dkGroupParse(m.text) : null;
@@ -6512,6 +6619,9 @@ var STR = {
6512
6619
  dirSearch: "search name / userid\u2026",
6513
6620
  dirLoading: "loading directory\u2026",
6514
6621
  noName: "no name given",
6622
+ friendRequestItem: "Friend request",
6623
+ showAll: "show all",
6624
+ showLess: "show less",
6515
6625
  dirEmpty: "nobody matches",
6516
6626
  dirError: "Could not load the directory:",
6517
6627
  bridgeEmpty: "Nobody else is listed on this bridge yet. You are the first.",
@@ -6711,6 +6821,9 @@ var STR = {
6711
6821
  dirSearch: "\u641C\u7D22\u540D\u5B57 / userid\u2026",
6712
6822
  dirLoading: "\u6B63\u5728\u52A0\u8F7D\u540D\u5355\u2026",
6713
6823
  noName: "\u5BF9\u65B9\u6CA1\u6709\u586B\u540D\u5B57",
6824
+ friendRequestItem: "\u597D\u53CB\u8BF7\u6C42",
6825
+ showAll: "\u5C55\u5F00\u5168\u6587",
6826
+ showLess: "\u6536\u8D77",
6714
6827
  dirEmpty: "\u6CA1\u6709\u5339\u914D\u7684\u4EBA",
6715
6828
  dirError: "\u540D\u5355\u52A0\u8F7D\u5931\u8D25\uFF1A",
6716
6829
  bridgeEmpty: "\u8FD9\u4E2A bridge \u4E0A\u8FD8\u6CA1\u6709\u522B\u4EBA\uFF0C\u4F60\u662F\u7B2C\u4E00\u4E2A\u3002",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/beagle-ui",
3
- "version": "0.2.35",
3
+ "version": "0.2.36",
4
4
  "description": "The Beagle chat UI, minus the machine it runs on — shared by the desktop install and the browser build.",
5
5
  "license": "MIT",
6
6
  "type": "module",