@cowwo/dsh-icon-custom 0.8.1 → 0.8.2
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/client/client.js +61 -8
- package/package.json +1 -1
package/client/client.js
CHANGED
|
@@ -300,6 +300,32 @@ window.__ModuleLoader__.load({
|
|
|
300
300
|
}
|
|
301
301
|
return changed;
|
|
302
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* The session the main view is showing.
|
|
305
|
+
*
|
|
306
|
+
* DSH 0.2.x carries NO `current` field in the session-list snapshot — it is
|
|
307
|
+
* written with exactly `ids` / `byId` / `phase` / `projectionsBySession`. The
|
|
308
|
+
* official signal is the row's `retainedBy.mainView` retention count, the same
|
|
309
|
+
* one ui-layout's DocumentTitle, ui-cordis, ui-open-in-app and ui-session read.
|
|
310
|
+
* Reading `list.current` here made `noteSeen()` a no-op, so the seen watermark
|
|
311
|
+
* never advanced and an unread dot could never be cleared by opening the
|
|
312
|
+
* session. Runtimes that do expose `current` are still honoured first.
|
|
313
|
+
* @param list - the session list snapshot (may be absent).
|
|
314
|
+
* @returns the id being viewed, or undefined.
|
|
315
|
+
*/
|
|
316
|
+
function currentSessionId(list) {
|
|
317
|
+
if (list === null || typeof list !== "object") return undefined;
|
|
318
|
+
if (typeof list.current === "string" && list.current !== "") return list.current;
|
|
319
|
+
const byId = list.byId;
|
|
320
|
+
if (byId === null || typeof byId !== "object") return undefined;
|
|
321
|
+
for (const session of Object.values(byId)) {
|
|
322
|
+
if (session === null || typeof session !== "object") continue;
|
|
323
|
+
const retainedBy = session.retainedBy;
|
|
324
|
+
const count = retainedBy !== null && typeof retainedBy === "object" ? retainedBy.mainView : undefined;
|
|
325
|
+
if (typeof count === "number" && count > 0) return session.id;
|
|
326
|
+
}
|
|
327
|
+
return undefined;
|
|
328
|
+
}
|
|
303
329
|
/**
|
|
304
330
|
* How many sessions deserve the badge right now: endings whose reason is
|
|
305
331
|
* enabled and that this browser has not seen since, plus sessions waiting
|
|
@@ -318,7 +344,7 @@ window.__ModuleLoader__.load({
|
|
|
318
344
|
/** { id, title, waiting, kind, at } — newest first, "in wait" ahead of "ended". */
|
|
319
345
|
const hits = [];
|
|
320
346
|
const ids = new Set();
|
|
321
|
-
const current = list
|
|
347
|
+
const current = currentSessionId(list);
|
|
322
348
|
const byId = list !== null && typeof list === "object" && list.byId !== null && typeof list.byId === "object" ? list.byId : {};
|
|
323
349
|
const titleOf = (id, entry) => (entry !== null && typeof entry === "object" && typeof entry.displayTitle === "string" && entry.displayTitle !== "" ? entry.displayTitle : id);
|
|
324
350
|
// Which workspace the session lives in. The sidebar's own workspace rows are
|
|
@@ -875,11 +901,28 @@ window.__ModuleLoader__.load({
|
|
|
875
901
|
* count simply drops back to 0.
|
|
876
902
|
*/
|
|
877
903
|
function BadgeSource(props) {
|
|
878
|
-
//
|
|
879
|
-
// (which carries every session's `lastTurnEnd` projection value)
|
|
880
|
-
//
|
|
904
|
+
// The hooks below are official root-scope standard props: the session list
|
|
905
|
+
// (which carries every session's `lastTurnEnd` projection value), the
|
|
906
|
+
// session-status map the sidebar row marker already uses, and the workspace
|
|
907
|
+
// snapshot that names each row.
|
|
881
908
|
const list = typeof props.useSessions === "function" ? props.useSessions((state) => state) : undefined;
|
|
882
|
-
|
|
909
|
+
// 0.2.x has no `useSessionPendingInteraction` — the string occurs nowhere in
|
|
910
|
+
// the runtime, so this half used to contribute nothing at all. The official
|
|
911
|
+
// replacement is the session-status map, whose rows carry `pendingInteraction`
|
|
912
|
+
// (alongside `completionUnread`, which the shipped sidebar reads too). Reshape
|
|
913
|
+
// it into the `id → { kind }` map `collectUnread` expects.
|
|
914
|
+
const status = typeof props.useSessionStatus === "function" ? props.useSessionStatus((map) => map) : undefined;
|
|
915
|
+
const pending = React.useMemo(() => {
|
|
916
|
+
const out = new Map();
|
|
917
|
+
if (status === null || status === undefined || typeof status.forEach !== "function") return out;
|
|
918
|
+
status.forEach((value, id) => {
|
|
919
|
+
const interaction = value !== null && typeof value === "object" ? value.pendingInteraction : undefined;
|
|
920
|
+
if (interaction === null || interaction === undefined) return;
|
|
921
|
+
const kind = typeof interaction === "object" && typeof interaction.kind === "string" ? interaction.kind : "";
|
|
922
|
+
out.set(id, { kind });
|
|
923
|
+
});
|
|
924
|
+
return out;
|
|
925
|
+
}, [status]);
|
|
883
926
|
const workspaces = typeof props.useWorkspaces === "function" ? props.useWorkspaces((state) => state) : undefined;
|
|
884
927
|
const [config, setConfig] = React.useState(unreadConfig);
|
|
885
928
|
React.useEffect(() => subscribeUnreadConfig(setConfig), []);
|
|
@@ -891,7 +934,7 @@ window.__ModuleLoader__.load({
|
|
|
891
934
|
saveSeenState();
|
|
892
935
|
}, [list]);
|
|
893
936
|
// Looking at a session marks it seen; the count also excludes it outright.
|
|
894
|
-
const currentId = list
|
|
937
|
+
const currentId = currentSessionId(list);
|
|
895
938
|
React.useEffect(() => {
|
|
896
939
|
if (noteSeen(currentId)) saveSeenState();
|
|
897
940
|
}, [currentId]);
|
|
@@ -1447,7 +1490,10 @@ window.__ModuleLoader__.load({
|
|
|
1447
1490
|
}
|
|
1448
1491
|
//#endregion
|
|
1449
1492
|
|
|
1450
|
-
|
|
1493
|
+
// `sessions` is gone from this list: its only use was the removed
|
|
1494
|
+
// `ctx.sessions.open(id)`. Navigation now goes through an optional
|
|
1495
|
+
// `ctx.get("uiWorkspace")` lookup instead of a hard dependency.
|
|
1496
|
+
const inject = ["slots", "locale", "connection"];
|
|
1451
1497
|
function apply(ctx) {
|
|
1452
1498
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-icon-custom: dictionaries");
|
|
1453
1499
|
const t = ctx.locale.bind(NS);
|
|
@@ -1495,8 +1541,15 @@ window.__ModuleLoader__.load({
|
|
|
1495
1541
|
// Additive seats for "where exactly?" — a foot entry beside the shipped
|
|
1496
1542
|
// Settings/Cordis buttons, and the frame-wide overlay for its list. A fresh
|
|
1497
1543
|
// id is added beside the others; nothing shipped is shadowed.
|
|
1544
|
+
//
|
|
1545
|
+
// 0.2.x has no `ctx.sessions.open(id)` (the ClientSessions service exposes
|
|
1546
|
+
// retain/using/retainInfo/refreshProjections/search/fork/scope/binding — no
|
|
1547
|
+
// navigation). Official code jumps to a session with
|
|
1548
|
+
// `ctx.uiWorkspace.openSession(id)` (ui-chat does exactly this), so the entry
|
|
1549
|
+
// is looked up optionally: navigation is best effort and must never make the
|
|
1550
|
+
// favicon half depend on the workspace UI being mounted.
|
|
1498
1551
|
const openSession = (id) => {
|
|
1499
|
-
try { ctx.
|
|
1552
|
+
try { ctx.get("uiWorkspace")?.openSession(id); } catch { /* navigation is best effort */ }
|
|
1500
1553
|
};
|
|
1501
1554
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register(
|
|
1502
1555
|
{ name: "sidebar.footer.action", id: "icon-custom-unread", order: 20, label: () => t("unreadPanelShort") },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cowwo/dsh-icon-custom",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "自定义浏览器标签页图标:在设置页上传 SVG/PNG/ICO,立即生效并持久保存,自动适配安卓/iOS/平板 PWA 图标。· Custom browser tab favicon: upload SVG/PNG/ICO from the settings page, applies instantly and persists, auto-sizes PWA icons for Android/iOS/tablets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|