@cowwo/dsh-icon-custom 0.10.0 → 0.10.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.
Files changed (2) hide show
  1. package/client/client.js +58 -7
  2. package/package.json +1 -1
package/client/client.js CHANGED
@@ -1229,7 +1229,8 @@ window.__ModuleLoader__.load({
1229
1229
  event.preventDefault();
1230
1230
  event.stopPropagation();
1231
1231
  const rect = node.getBoundingClientRect();
1232
- toggleUnreadPanel({ left: rect.left, top: rect.top });
1232
+ // `bottom` is what the panel drops below; see unreadPanelPlacement.
1233
+ toggleUnreadPanel({ left: rect.left, top: rect.top, bottom: rect.bottom });
1233
1234
  });
1234
1235
  }
1235
1236
  const count = effectiveCount();
@@ -1284,6 +1285,52 @@ window.__ModuleLoader__.load({
1284
1285
  headerBadgeHost = null;
1285
1286
  headerBadgeHostPosition = "";
1286
1287
  }
1288
+ /** Gap between the panel and whatever it is anchored to. */
1289
+ const UNREAD_PANEL_GAP = 6;
1290
+ /** Breathing room from the window edges. */
1291
+ const UNREAD_PANEL_MARGIN = 8;
1292
+ /** The panel's practical width (between its minWidth and maxWidth below). */
1293
+ const UNREAD_PANEL_WIDTH = 300;
1294
+ /** How tall the scrolling session list may get before it scrolls. */
1295
+ const UNREAD_PANEL_LIST_MAX = 320;
1296
+
1297
+ /**
1298
+ * Where the unread panel goes, in viewport coordinates.
1299
+ *
1300
+ * It opens DOWNWARD from the badge. The original math pinned the panel's
1301
+ * BOTTOM edge just above the anchor — correct while the trigger sat in the
1302
+ * sidebar footer, and wrong the moment that trigger moved to the section
1303
+ * header: the same formula then parked the panel's bottom near the top of the
1304
+ * window and grew the panel upward, off the top of the screen (the title and
1305
+ * the first workspace heading were what got cut off). Anchoring on the
1306
+ * anchor's `bottom` is what drops it below the badge instead.
1307
+ *
1308
+ * Horizontally it stays clear of the sidebar: the panel is a frame-wide
1309
+ * overlay, and covering the sidebar — and the very badge that opened it — was
1310
+ * the other half of the complaint.
1311
+ * @param anchor - the badge's viewport rect (`{left, top, bottom}`), or null.
1312
+ * @param sidebarRight - the browsing region's right edge, or null.
1313
+ * @param viewportWidth - window width.
1314
+ * @param viewportHeight - window height.
1315
+ * @returns `{ left, top, listMaxHeight }` in viewport pixels.
1316
+ */
1317
+ function unreadPanelPlacement(anchor, sidebarRight, viewportWidth, viewportHeight) {
1318
+ let left = UNREAD_PANEL_MARGIN;
1319
+ let top = UNREAD_PANEL_MARGIN;
1320
+ if (anchor !== null && typeof anchor === "object") {
1321
+ if (typeof anchor.left === "number") left = anchor.left;
1322
+ const below = typeof anchor.bottom === "number" ? anchor.bottom : anchor.top;
1323
+ if (typeof below === "number") top = below + UNREAD_PANEL_GAP;
1324
+ }
1325
+ if (typeof sidebarRight === "number" && sidebarRight > 0) left = Math.max(left, sidebarRight + UNREAD_PANEL_GAP);
1326
+ left = Math.max(UNREAD_PANEL_MARGIN, Math.min(left, viewportWidth - UNREAD_PANEL_WIDTH - UNREAD_PANEL_MARGIN));
1327
+ top = Math.max(UNREAD_PANEL_MARGIN, top);
1328
+ // Never taller than what is left below the panel's own top, so a long list
1329
+ // scrolls inside the panel instead of pushing it off the bottom edge.
1330
+ const listMaxHeight = Math.max(120, Math.min(UNREAD_PANEL_LIST_MAX, viewportHeight - top - 72));
1331
+ return { left: Math.round(left), top: Math.round(top), listMaxHeight: Math.round(listMaxHeight) };
1332
+ }
1333
+
1287
1334
  /**
1288
1335
  * The list behind that number, in the frame-wide overlay layer so it escapes
1289
1336
  * the sidebar's clipping and scroll container. Clicking a row opens that
@@ -1312,22 +1359,26 @@ window.__ModuleLoader__.load({
1312
1359
  if (!open) return null;
1313
1360
  const t = props.t;
1314
1361
  const anchor = unreadPanelAnchor;
1362
+ // Measured, not assumed: the panel has to clear whatever width the sidebar
1363
+ // currently has (it is resizable and collapsible).
1364
+ let sidebarRight = null;
1365
+ try {
1366
+ const region = workspaceDotContainer();
1367
+ if (region !== null) sidebarRight = region.getBoundingClientRect().right;
1368
+ } catch { /* measurement is best effort; the margin fallback still applies */ }
1369
+ const place = unreadPanelPlacement(anchor, sidebarRight, window.innerWidth, window.innerHeight);
1315
1370
  const style = {
1316
- position: "fixed", left: "12px", bottom: "52px", zIndex: 60, pointerEvents: "auto",
1371
+ position: "fixed", left: place.left + "px", top: place.top + "px", zIndex: 60, pointerEvents: "auto",
1317
1372
  minWidth: "240px", maxWidth: "340px", padding: "8px", borderRadius: "12px",
1318
1373
  border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-1)",
1319
1374
  boxShadow: "0 10px 30px rgba(0,0,0,.18)", color: "var(--dsw-alias-label-primary)", fontSize: "12px"
1320
1375
  };
1321
- if (anchor !== null && typeof anchor === "object") {
1322
- style.left = Math.max(8, Math.round(anchor.left)) + "px";
1323
- style.bottom = Math.max(8, Math.round(window.innerHeight - anchor.top + 6)) + "px";
1324
- }
1325
1376
  const items = Array.isArray(snapshot.items) ? snapshot.items : [];
1326
1377
  return React.createElement("div", { "data-icon-custom-unread": "1", style },
1327
1378
  React.createElement("div", { style: { fontWeight: 600, padding: "2px 6px 8px" } }, t("unreadPanelTitle")),
1328
1379
  items.length === 0
1329
1380
  ? React.createElement("div", { style: { padding: "2px 6px 8px", opacity: 0.7 } }, t("unreadPanelEmpty"))
1330
- : React.createElement("div", { style: { display: "flex", flexDirection: "column", maxHeight: "320px", overflowY: "auto" } },
1381
+ : React.createElement("div", { style: { display: "flex", flexDirection: "column", maxHeight: place.listMaxHeight + "px", overflowY: "auto" } },
1331
1382
  groupUnreadByWorkspace(items).map((group) => React.createElement("div", { key: group.where === "" ? "\u0000none" : group.where },
1332
1383
  React.createElement("div", { style: { padding: "7px 8px 3px", fontSize: "11px", fontWeight: 600, opacity: 0.55, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } },
1333
1384
  group.where === "" ? t("unreadPanelOther") : group.where
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cowwo/dsh-icon-custom",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
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",