@duke-dsh-plugins/dsh-archive-manager 1.3.4 → 1.3.6

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.js +47 -18
  2. package/package.json +1 -1
package/client.js CHANGED
@@ -3,7 +3,10 @@
3
3
  *
4
4
  * Rendered by the DSH web shell via `window.__ModuleLoader__.load`. Registers:
5
5
  * - a sidebar footer action button (archived-session entry),
6
- * - a frame-wide archive manager panel (search / group / restore / delete).
6
+ * - a frame-wide archive manager panel (search / group / restore / delete),
7
+ * rendered together with the button from the sidebar.footer.action slot —
8
+ * mirroring how ui-settings renders its modal from sidebar.settings (see
9
+ * the registration comment for the stacking-context rationale).
7
10
  *
8
11
  * The panel mirrors the DSH 工作区 (workspace) browsing region: a dialog
9
12
  * surface using the same design tokens as the workspace browser — folder
@@ -26,8 +29,15 @@ window.__ModuleLoader__.load({
26
29
  const CSS = `
27
30
  [class*="footerActions"]{flex-direction:column;align-items:center;}
28
31
 
29
- /* Overlay — same mask surface as DSH Modal */
30
- .am-overlay{position:fixed;inset:0;z-index:2147483000;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.4));backdrop-filter:var(--dsw-mask-blur,blur(2px));display:flex;align-items:center;justify-content:center;padding:24px;}
32
+ /* Overlay — same mask surface as DSH Modal, same z-index tier as the DSH
33
+ settings overlay (1000). This layer MUST be rendered from a slot that sits
34
+ outside any stacking context (the sidebar foot, like Settings does), never
35
+ from the shell.overlay slot: AppFrame renders that slot inside its
36
+ .overlayLayer (position:absolute;z-index:20, a stacking context), which
37
+ traps any child z-index below it — dsh-better-sidebar appends a
38
+ position:fixed;z-index:25 layer to document.body and would cover the
39
+ modal. */
40
+ .am-overlay{position:fixed;inset:0;z-index:1000;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.4));backdrop-filter:var(--dsw-mask-blur,blur(2px));display:flex;align-items:center;justify-content:center;padding:24px;}
31
41
 
32
42
  /* Panel — same surface & size as the DSH Settings dialog (width 800px) */
33
43
  .am-panel{position:relative;display:flex;flex-direction:column;width:800px;max-width:calc(100vw - 48px);height:min(800px,100vh - 48px);overflow:hidden;border:1px solid var(--dsw-alias-border-inverted,rgba(128,128,128,.3));border-radius:24px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,inherit);box-shadow:var(--dsw-shadow-lv3,0 12px 40px rgba(0,0,0,.25));}
@@ -465,7 +475,18 @@ window.__ModuleLoader__.load({
465
475
  );
466
476
  }
467
477
 
468
- // Sidebar footer action entry (Cordis Plugin 下方、设置上方;纵向排列由注入 CSS 保证)。
478
+ // Sidebar footer action entry (Cordis Plugin 下方、设置上方;纵向排列由注入
479
+ // CSS 保证) + frame-wide archive manager panel.
480
+ //
481
+ // 弹窗为什么从这里渲染而不是 `shell.overlay`:AppFrame 把 `shell.overlay`
482
+ // 渲染在 `.overlayLayer`(position:absolute; z-index:20)内,该层形成独立
483
+ // stacking context,把子元素 z-index 锁死在其下;而 dsh-better-sidebar 把
484
+ // 整层 append 到 document.body(position:fixed; z-index:25),归档弹窗因此
485
+ // 会被它盖住。设置弹窗(ui-settings)的做法是把全屏 fixed 遮罩
486
+ // (z-index:1000)从 sidebar.settings 槽渲染——侧栏列不构成 stacking
487
+ // context,fixed 层直接参与根 stacking context,压过 better-sidebar 的 25。
488
+ // 这里照搬同一做法:弹窗与按钮同从 sidebar.footer.action 槽渲染,两者共享
489
+ // useOpen 状态,UI 行为不变。
469
490
  ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register(
470
491
  { name: "sidebar.footer.action", id: "archive-manager", order: 500, label: () => "归档" },
471
492
  (props) => {
@@ -477,11 +498,25 @@ window.__ModuleLoader__.load({
477
498
  const count = rawCount - (ghostIds.length > rawCount ? rawCount : ghostIds.length);
478
499
  const safeCount = count > 0 ? count : 0;
479
500
  const isOpen = useOpen();
501
+ // Esc 关闭弹窗:打开期间在 document 捕获阶段监听 keydown,命中
502
+ // Escape 即关闭并 stopPropagation——弹窗位于 z-index:1000 顶层,
503
+ // 此时 Esc 应只作用于它,不穿透到 shell 的全局快捷键或底层输入框。
504
+ React.useEffect(() => {
505
+ if (!isOpen) return undefined;
506
+ const onKeyDown = (e) => {
507
+ if (e.key === "Escape") {
508
+ e.stopPropagation();
509
+ setOpen(false);
510
+ }
511
+ };
512
+ document.addEventListener("keydown", onKeyDown, true);
513
+ return () => document.removeEventListener("keydown", onKeyDown, true);
514
+ }, [isOpen]);
480
515
  const children = [];
481
516
  children.push(React.createElement("span", { key: "icon", className: "am-foot-icon", "aria-hidden": true }, React.createElement(ArchiveIcon)));
482
517
  if (wide) children.push(React.createElement("span", { key: "label", className: "am-foot-label" }, "归档"));
483
518
  if (wide && safeCount > 0) children.push(React.createElement("span", { key: "cnt", className: "am-badge" }, String(safeCount)));
484
- return React.createElement(
519
+ const button = React.createElement(
485
520
  "div", { className: "am-foot-layer" + (wide ? "" : " am-foot-rail") },
486
521
  React.createElement("button", {
487
522
  type: "button",
@@ -491,19 +526,13 @@ window.__ModuleLoader__.load({
491
526
  className: "am-foot" + (isOpen ? " am-active" : ""),
492
527
  }, children)
493
528
  );
494
- }
495
- ));
496
-
497
- // Frame-wide archive manager panel.
498
- ctx.slots.inject("shell.overlay", () => ctx.slots.register(
499
- { name: "shell.overlay", id: "archive-manager", order: 200 },
500
- (props) => {
501
- const isOpen = useOpen();
502
- if (!isOpen) return null;
503
- return React.createElement(
504
- "div", { className: "am-overlay", onClick: () => setOpen(false) },
505
- React.createElement(ArchiveManager, { slotProps: props, onClose: () => setOpen(false) })
506
- );
529
+ const overlay = isOpen
530
+ ? React.createElement(
531
+ "div", { className: "am-overlay", onClick: () => setOpen(false) },
532
+ React.createElement(ArchiveManager, { slotProps: props, onClose: () => setOpen(false) })
533
+ )
534
+ : null;
535
+ return [button, overlay];
507
536
  }
508
537
  ));
509
538
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duke-dsh-plugins/dsh-archive-manager",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "Archive manager for DeepSeek Harness: group archived sessions by project, newest-first, with search, restore and delete.",
5
5
  "repository": {
6
6
  "type": "git",