@weniatall/dsh-file-viewer 0.3.8 → 0.3.12

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/lib/client.js +183 -6
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -348,6 +348,10 @@ window.__ModuleLoader__.load({
348
348
  const DEFAULT_TREE_WIDTH = 280;
349
349
  const MIN_TREE_WIDTH = 160;
350
350
  const MAX_TREE_WIDTH = 700;
351
+ const GIT_CHANGES_HEIGHT_KEY = "dsh-file-viewer.git-changes-height";
352
+ const DEFAULT_GIT_CHANGES_HEIGHT = 180;
353
+ const MIN_GIT_CHANGES_HEIGHT = 64;
354
+ const MAX_GIT_CHANGES_HEIGHT = 800;
351
355
  /**
352
356
  * Smallest width the drawer may be dragged to.
353
357
  *
@@ -387,7 +391,7 @@ window.__ModuleLoader__.load({
387
391
  body>div[role="presentation"]:has(.fv-scrim)>[aria-hidden="true"]{display:none!important}
388
392
  .fv-scrim[role="dialog"]{position:absolute!important;inset:0!important;width:auto!important;max-width:none!important;max-height:none!important;min-height:0!important;margin:0!important;border:none!important;border-radius:0!important;box-shadow:none!important;background:transparent!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important;overflow:visible!important}
389
393
  .fv-scrim{position:absolute;inset:0;z-index:40;display:flex;align-items:stretch;justify-content:flex-end;background:transparent;pointer-events:auto;animation:fv-fade .16s ease-out}
390
- .fv-shell{display:flex;flex-direction:column;width:min(64vw,1100px);min-width:0;min-height:0;overflow:hidden;border-left:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));box-shadow:var(--dsw-shadow-lv3);font-family:var(--dsw-font-family);color:var(--dsw-alias-label-primary);-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);animation:fv-slide .2s cubic-bezier(.2,.8,.2,1);transition:width .2s cubic-bezier(.2,.8,.2,1)}
394
+ .fv-shell{display:flex;flex-direction:column;width:min(64vw,1100px);min-width:0;min-height:0;overflow:hidden;border-left:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));box-shadow:var(--dsw-shadow-lv3);font-family:var(--dsw-font-family);color:var(--dsw-alias-label-primary);animation:fv-slide .2s cubic-bezier(.2,.8,.2,1);transition:width .2s cubic-bezier(.2,.8,.2,1)}
391
395
  .fv-shell[data-fullscreen="true"]{width:100vw;border-left:none}
392
396
  /* The leading edge is the drawer's own resize handle. It is positioned
393
397
  over the border rather than beside it so the panel does not shift when
@@ -635,7 +639,19 @@ window.__ModuleLoader__.load({
635
639
  .fv-commit-tag{flex:none;padding:1px 6px;border-radius:6px;background:var(--dsw-alias-bg-layer-3,rgba(0,0,0,.05));color:var(--dsw-alias-label-caption);font-family:var(--dsw-font-family);font-size:10px}
636
640
  /* Working-tree changes and a commit's patch share the commit-row visuals
637
641
  so the two panels read as one surface. */
638
- .fv-git-changes{display:flex;flex:none;flex-direction:column;gap:1px;max-height:38%;overflow-y:auto;overscroll-behavior:contain;border-bottom:1px solid var(--dsw-alias-border-l1);padding-bottom:4px}
642
+ .fv-git-changes{display:flex;flex:none;flex-direction:column;gap:1px;min-height:48px;overflow-y:auto;overscroll-behavior:contain;padding-bottom:2px}
643
+ .fv-git-panel[data-v-resizing="true"]{cursor:row-resize!important;user-select:none!important}
644
+ .fv-git-panel[data-v-resizing="true"] *{pointer-events:none!important}
645
+ .fv-git-panel[data-v-resizing="true"] .fv-git-v-resizer,
646
+ .fv-git-panel[data-v-resizing="true"] .fv-git-v-resizer *{pointer-events:auto!important}
647
+ .fv-git-v-resizer{position:relative;flex:none;display:flex;align-items:center;justify-content:center;height:14px;margin:2px 0;cursor:row-resize;user-select:none;touch-action:none;z-index:3}
648
+ .fv-git-v-resizer-line{position:absolute;left:0;right:0;top:50%;height:1px;background:var(--dsw-alias-border-l1);transform:translateY(-50%);transition:background-color .15s ease;pointer-events:none}
649
+ .fv-git-v-resizer-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:13px;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));box-shadow:0 1px 3px rgba(0,0,0,.08);cursor:row-resize;pointer-events:auto;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease;z-index:2}
650
+ .fv-git-v-resizer-grip{display:block;width:14px;height:2px;border-radius:1px;background:var(--dsw-alias-label-caption);box-shadow:0 -3px 0 0 var(--dsw-alias-label-caption);pointer-events:none}
651
+ .fv-git-v-resizer:hover .fv-git-v-resizer-line,.fv-git-v-resizer[data-dragging="true"] .fv-git-v-resizer-line{background:var(--dsw-alias-brand-primary,#4d6bfe)}
652
+ .fv-git-v-resizer:hover .fv-git-v-resizer-btn,.fv-git-v-resizer[data-dragging="true"] .fv-git-v-resizer-btn,.fv-git-v-resizer-btn:hover{border-color:var(--dsw-alias-brand-primary,#4d6bfe);background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:0 1px 6px color-mix(in srgb,var(--dsw-alias-brand-primary,#4d6bfe) 35%,transparent)}
653
+ .fv-git-v-resizer:hover .fv-git-v-resizer-grip,.fv-git-v-resizer[data-dragging="true"] .fv-git-v-resizer-grip,.fv-git-v-resizer-btn:hover .fv-git-v-resizer-grip{background:var(--dsw-alias-brand-primary,#4d6bfe);box-shadow:0 -3px 0 0 var(--dsw-alias-brand-primary,#4d6bfe)}
654
+ .fv-git-v-resizer:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4d6bfe);outline-offset:-1px}
639
655
  .fv-git-change-group{display:flex;flex-direction:column;gap:1px}
640
656
  .fv-git-refresh{width:22px;height:22px;margin-left:auto}
641
657
  .fv-commit-diff{display:flex;flex:1 1 auto;flex-direction:column;gap:2px;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:4px 6px}
@@ -841,7 +857,8 @@ window.__ModuleLoader__.load({
841
857
  .fv-git-more{height:38px!important;font-size:13px!important}
842
858
  .fv-commit-file{min-height:42px!important;font-size:13.5px!important}
843
859
  .fv-commit-path{font-size:12px!important}
844
- .fv-git-changes{max-height:none!important}
860
+ .fv-git-changes{height:auto!important;max-height:none!important}
861
+ .fv-git-v-resizer{display:none!important}
845
862
  .fv-commit-diff-file .fv-diff-table{font-size:12px!important}
846
863
  }
847
864
  `;
@@ -1148,6 +1165,27 @@ window.__ModuleLoader__.load({
1148
1165
  } catch { /* storage is unavailable */ }
1149
1166
  }
1150
1167
 
1168
+ function readGitChangesHeight() {
1169
+ try {
1170
+ const raw = globalThis.localStorage?.getItem(GIT_CHANGES_HEIGHT_KEY);
1171
+ const parsed = Number(raw);
1172
+ if (Number.isFinite(parsed) && parsed >= MIN_GIT_CHANGES_HEIGHT && parsed <= MAX_GIT_CHANGES_HEIGHT) {
1173
+ return Math.round(parsed);
1174
+ }
1175
+ } catch { /* storage is unavailable */ }
1176
+ return DEFAULT_GIT_CHANGES_HEIGHT;
1177
+ }
1178
+
1179
+ function writeGitChangesHeight(height) {
1180
+ try {
1181
+ if (typeof height === "number" && Number.isFinite(height)) {
1182
+ globalThis.localStorage?.setItem(GIT_CHANGES_HEIGHT_KEY, String(Math.round(height)));
1183
+ } else {
1184
+ globalThis.localStorage?.removeItem(GIT_CHANGES_HEIGHT_KEY);
1185
+ }
1186
+ } catch { /* storage is unavailable */ }
1187
+ }
1188
+
1151
1189
  /**
1152
1190
  * Read the per-file language overrides.
1153
1191
  *
@@ -2310,10 +2348,72 @@ window.__ModuleLoader__.load({
2310
2348
  const canCheckout = repo !== null && viewingBranch !== "" && viewingBranch !== current
2311
2349
  && checkoutable && state.busy !== true;
2312
2350
 
2351
+ const [changesHeight, setChangesHeight] = react.useState(readGitChangesHeight);
2352
+ const [isResizingChanges, setIsResizingChanges] = react.useState(false);
2353
+ const changesResizeRef = react.useRef(null);
2354
+ const changesHeightRef = react.useRef(changesHeight);
2355
+ changesHeightRef.current = changesHeight;
2356
+
2357
+ const onChangesResizerPointerDown = (event) => {
2358
+ if (event.button !== 0 && event.button !== undefined) return;
2359
+ event.preventDefault();
2360
+ event.stopPropagation();
2361
+ const startY = event.clientY;
2362
+ const startH = changesHeightRef.current;
2363
+ changesResizeRef.current = { startY, startH };
2364
+ setIsResizingChanges(true);
2365
+ try { event.currentTarget.setPointerCapture(event.pointerId); } catch (_) {}
2366
+ };
2367
+
2368
+ const onChangesResizerPointerMove = (event) => {
2369
+ if (!changesResizeRef.current) return;
2370
+ const { startY, startH } = changesResizeRef.current;
2371
+ const deltaY = event.clientY - startY;
2372
+ const panelEl = event.currentTarget.closest(".fv-git-panel");
2373
+ const panelHeight = panelEl ? panelEl.clientHeight : 600;
2374
+ const maxBound = Math.max(MIN_GIT_CHANGES_HEIGHT, panelHeight - 140);
2375
+ const nextH = Math.round(Math.min(Math.min(MAX_GIT_CHANGES_HEIGHT, maxBound), Math.max(MIN_GIT_CHANGES_HEIGHT, startH + deltaY)));
2376
+ setChangesHeight(nextH);
2377
+ };
2378
+
2379
+ const onChangesResizerPointerUp = (event) => {
2380
+ if (!changesResizeRef.current) return;
2381
+ changesResizeRef.current = null;
2382
+ setIsResizingChanges(false);
2383
+ try { event.currentTarget.releasePointerCapture(event.pointerId); } catch (_) {}
2384
+ writeGitChangesHeight(changesHeightRef.current);
2385
+ };
2386
+
2387
+ const onChangesResizerDoubleClick = (event) => {
2388
+ event.preventDefault();
2389
+ event.stopPropagation();
2390
+ setChangesHeight(DEFAULT_GIT_CHANGES_HEIGHT);
2391
+ writeGitChangesHeight(DEFAULT_GIT_CHANGES_HEIGHT);
2392
+ };
2393
+
2394
+ const onChangesResizerKeyDown = (event) => {
2395
+ if (event.key === "ArrowUp") {
2396
+ event.preventDefault();
2397
+ const nextH = Math.max(MIN_GIT_CHANGES_HEIGHT, changesHeightRef.current - 16);
2398
+ setChangesHeight(nextH);
2399
+ writeGitChangesHeight(nextH);
2400
+ } else if (event.key === "ArrowDown") {
2401
+ event.preventDefault();
2402
+ const nextH = Math.min(MAX_GIT_CHANGES_HEIGHT, changesHeightRef.current + 16);
2403
+ setChangesHeight(nextH);
2404
+ writeGitChangesHeight(nextH);
2405
+ } else if (event.key === "Home" || event.key === "Enter") {
2406
+ event.preventDefault();
2407
+ setChangesHeight(DEFAULT_GIT_CHANGES_HEIGHT);
2408
+ writeGitChangesHeight(DEFAULT_GIT_CHANGES_HEIGHT);
2409
+ }
2410
+ };
2411
+
2313
2412
  const wrap = (...children) => react.createElement("div", {
2314
2413
  className: "fv-tree fv-git-panel",
2315
2414
  role: "group",
2316
2415
  "aria-label": "Git 面板",
2416
+ "data-v-resizing": isResizingChanges ? "true" : "false",
2317
2417
  style: typeof width === "number" ? { width: width + "px" } : undefined,
2318
2418
  }, header, ...children);
2319
2419
 
@@ -2451,7 +2551,14 @@ window.__ModuleLoader__.load({
2451
2551
  : null);
2452
2552
  }
2453
2553
 
2454
- const changesSection = react.createElement("div", { className: "fv-git-changes" },
2554
+ const changesSection = react.createElement("div", {
2555
+ className: "fv-git-changes",
2556
+ style: {
2557
+ height: changesHeight + "px",
2558
+ maxHeight: "none",
2559
+ flex: "none",
2560
+ },
2561
+ },
2455
2562
  react.createElement("div", { className: "fv-git-section" },
2456
2563
  react.createElement("span", null, "工作区改动"),
2457
2564
  react.createElement("span", { className: "fv-git-count" },
@@ -2465,6 +2572,37 @@ window.__ModuleLoader__.load({
2465
2572
  }, react.createElement(SvgIconRefresh, { size: 13 }))),
2466
2573
  changesBody);
2467
2574
 
2575
+ const vResizer = react.createElement("div", {
2576
+ className: "fv-git-v-resizer",
2577
+ role: "separator",
2578
+ tabIndex: 0,
2579
+ "aria-orientation": "horizontal",
2580
+ "aria-label": "调整工作区改动与提交记录高度",
2581
+ "aria-valuenow": changesHeight,
2582
+ "aria-valuemin": MIN_GIT_CHANGES_HEIGHT,
2583
+ "aria-valuemax": MAX_GIT_CHANGES_HEIGHT,
2584
+ title: "拖动调整区域高度,双击恢复默认",
2585
+ "data-dragging": isResizingChanges ? "true" : "false",
2586
+ onPointerDown: onChangesResizerPointerDown,
2587
+ onPointerMove: onChangesResizerPointerMove,
2588
+ onPointerUp: onChangesResizerPointerUp,
2589
+ onPointerCancel: onChangesResizerPointerUp,
2590
+ onDoubleClick: onChangesResizerDoubleClick,
2591
+ onKeyDown: onChangesResizerKeyDown,
2592
+ },
2593
+ react.createElement("div", { className: "fv-git-v-resizer-line" }),
2594
+ react.createElement("button", {
2595
+ type: "button",
2596
+ tabIndex: -1,
2597
+ className: "fv-git-v-resizer-btn",
2598
+ "aria-label": "拖动手柄",
2599
+ title: "按住拖动调整高度,双击恢复默认",
2600
+ "data-dragging": isResizingChanges ? "true" : "false",
2601
+ },
2602
+ react.createElement("span", { className: "fv-git-v-resizer-grip" })
2603
+ )
2604
+ );
2605
+
2468
2606
  const commitRows = commits.map((commit) => react.createElement("button", {
2469
2607
  key: commit.sha,
2470
2608
  type: "button",
@@ -2511,6 +2649,7 @@ window.__ModuleLoader__.load({
2511
2649
 
2512
2650
  return wrap(toolbar,
2513
2651
  changesSection,
2652
+ vResizer,
2514
2653
  react.createElement("div", { className: "fv-git-section" },
2515
2654
  react.createElement("span", null, "提交记录"),
2516
2655
  react.createElement("span", { className: "fv-git-count" }, state.total > 0 ? String(state.total) : "")),
@@ -3350,7 +3489,20 @@ window.__ModuleLoader__.load({
3350
3489
  return react.createElement(react.Fragment, null,
3351
3490
  react.createElement("div", {
3352
3491
  className: "fv-context-backdrop",
3492
+ onPointerDown: (event) => {
3493
+ event.preventDefault();
3494
+ event.stopPropagation();
3495
+ if (Date.now() - mountTimeRef.current < 400) return;
3496
+ onClose();
3497
+ },
3498
+ onMouseDown: (event) => {
3499
+ event.preventDefault();
3500
+ event.stopPropagation();
3501
+ if (Date.now() - mountTimeRef.current < 400) return;
3502
+ onClose();
3503
+ },
3353
3504
  onClick: (event) => {
3505
+ event.preventDefault();
3354
3506
  event.stopPropagation();
3355
3507
  if (Date.now() - mountTimeRef.current < 400) return;
3356
3508
  onClose();
@@ -4452,7 +4604,20 @@ window.__ModuleLoader__.load({
4452
4604
  return react.createElement(react.Fragment, null,
4453
4605
  react.createElement("div", {
4454
4606
  className: "fv-context-backdrop",
4607
+ onPointerDown: (e) => {
4608
+ e.preventDefault();
4609
+ e.stopPropagation();
4610
+ if (Date.now() - mountTimeRef.current < 400) return;
4611
+ onClose();
4612
+ },
4613
+ onMouseDown: (e) => {
4614
+ e.preventDefault();
4615
+ e.stopPropagation();
4616
+ if (Date.now() - mountTimeRef.current < 400) return;
4617
+ onClose();
4618
+ },
4455
4619
  onClick: (e) => {
4620
+ e.preventDefault();
4456
4621
  e.stopPropagation();
4457
4622
  if (Date.now() - mountTimeRef.current < 400) return;
4458
4623
  onClose();
@@ -4867,6 +5032,15 @@ window.__ModuleLoader__.load({
4867
5032
  // it. Kept apart from the tree's `contextMenu`: the two menus describe
4868
5033
  // different subjects and must never be confused for one another.
4869
5034
  const [tabMenu, setTabMenu] = react.useState(null);
5035
+ const lastMenuClosedAtRef = react.useRef(0);
5036
+ const closeContextMenu = react.useCallback(() => {
5037
+ lastMenuClosedAtRef.current = Date.now();
5038
+ setContextMenu(null);
5039
+ }, []);
5040
+ const closeTabMenu = react.useCallback(() => {
5041
+ lastMenuClosedAtRef.current = Date.now();
5042
+ setTabMenu(null);
5043
+ }, []);
4870
5044
  const tabsRef = react.useRef(null);
4871
5045
  tabsRef.current = tabs;
4872
5046
  const activeTabIdRef = react.useRef("");
@@ -5816,6 +5990,8 @@ window.__ModuleLoader__.load({
5816
5990
  onMouseDown: (event) => {
5817
5991
  if (event.target !== event.currentTarget) return;
5818
5992
  if (Date.now() - openedAtRef.current < 400) return;
5993
+ if (contextMenu !== null || tabMenu !== null) return;
5994
+ if (Date.now() - lastMenuClosedAtRef.current < 400) return;
5819
5995
  openStore.set(null);
5820
5996
  },
5821
5997
  },
@@ -6097,7 +6273,7 @@ window.__ModuleLoader__.load({
6097
6273
  ? react.createElement(ContextMenu, {
6098
6274
  menu: contextMenu,
6099
6275
  rootPath: activeRoot ? (activeRoot.path || activeRoot.id) : root,
6100
- onClose: () => setContextMenu(null),
6276
+ onClose: closeContextMenu,
6101
6277
  onMention: mention,
6102
6278
  onToast: showToast,
6103
6279
  onDownload: handleDownloadItem,
@@ -6110,7 +6286,7 @@ window.__ModuleLoader__.load({
6110
6286
  ? react.createElement(TabContextMenu, {
6111
6287
  menu: tabMenu,
6112
6288
  tabs,
6113
- onClose: () => setTabMenu(null),
6289
+ onClose: closeTabMenu,
6114
6290
  onAction: onTabAction,
6115
6291
  })
6116
6292
  : null,
@@ -6424,6 +6600,7 @@ window.__ModuleLoader__.load({
6424
6600
  mediaTypeOf, messageOf, createStore, createRequest, blobOf, ensureStyles,
6425
6601
  ENTRY_POSITION_KEY, DRAG_SLOP, settleEntry, readEntryPosition, writeEntryPosition,
6426
6602
  TREE_WIDTH_KEY, DEFAULT_TREE_WIDTH, MIN_TREE_WIDTH, MAX_TREE_WIDTH, readTreeWidth, writeTreeWidth,
6603
+ GIT_CHANGES_HEIGHT_KEY, DEFAULT_GIT_CHANGES_HEIGHT, MIN_GIT_CHANGES_HEIGHT, MAX_GIT_CHANGES_HEIGHT, readGitChangesHeight, writeGitChangesHeight,
6427
6604
  SHELL_WIDTH_KEY, MIN_SHELL_WIDTH, readShellWidth, writeShellWidth, clampShellWidth,
6428
6605
  LANG_OVERRIDES_KEY, LANG_OVERRIDES_MAX, readLangOverrides, writeLangOverrides, readLangOverride, writeLangOverride,
6429
6606
  langOverrideKey, isKnownLanguageId, setLanguageCatalog, getLanguageCatalog: () => languageCatalog, LanguagePicker,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weniatall/dsh-file-viewer",
3
- "version": "0.3.8",
3
+ "version": "0.3.12",
4
4
  "description": "Workspace file viewer and Git panel for DeepSeek Harness: file tree, syntax-highlighted code, images, PDF, Excel and Word, plus local/remote branches, paged commit history, commit diffs, working-tree changes and changed-file navigation",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",