@co0ontty/wand 1.21.18 → 1.22.0

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.
@@ -1350,7 +1350,7 @@
1350
1350
  ) +
1351
1351
  '</div>' +
1352
1352
  '<div class="topbar-right">' +
1353
- (selectedSession && selectedSession.cwd ? '<button id="topbar-file-button" class="topbar-btn square' + (state.filePanelOpen ? ' active' : '') + '" type="button" aria-label="文件" title="文件"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg></button>' : '') +
1353
+ '<button id="topbar-file-button" class="topbar-btn square' + (state.filePanelOpen ? ' active' : '') + '" type="button" aria-label="文件" title="查看文件(可修改路径)"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg></button>' +
1354
1354
  '<span id="topbar-git-slot" class="topbar-git-slot">' + renderTopbarGitBadgeHtml() + '</span>' +
1355
1355
  (selectedSession ? renderTopbarMoreMenuHtml(selectedSession) : '') +
1356
1356
  '</div>' +
@@ -1366,7 +1366,7 @@
1366
1366
  '<div class="file-side-panel-body">' +
1367
1367
  '<div class="file-explorer-header">' +
1368
1368
  '<button class="file-explorer-up" id="file-explorer-up" type="button" title="返回上级目录" aria-label="返回上级目录">⬆</button>' +
1369
- '<span class="file-explorer-path" id="file-explorer-cwd" title="' + escapeHtml(selectedSession && selectedSession.cwd ? selectedSession.cwd : getConfigCwd()) + '">' + escapeHtml(selectedSession && selectedSession.cwd ? selectedSession.cwd : getConfigCwd()) + '</span>' +
1369
+ '<input type="text" class="file-explorer-path" id="file-explorer-cwd" value="' + escapeHtml(selectedSession && selectedSession.cwd ? selectedSession.cwd : getConfigCwd()) + '" title="' + escapeHtml(selectedSession && selectedSession.cwd ? selectedSession.cwd : getConfigCwd()) + '" placeholder="输入路径并回车..." spellcheck="false" autocomplete="off" autocapitalize="off" autocorrect="off" aria-label="当前路径,可直接修改后回车" />' +
1370
1370
  '<button class="file-explorer-toggle-hidden' + (state.fileExplorerShowHidden ? ' active' : '') + '" id="file-explorer-toggle-hidden" type="button" title="' + (state.fileExplorerShowHidden ? "隐藏点开头文件" : "显示隐藏文件") + '" aria-pressed="' + (state.fileExplorerShowHidden ? "true" : "false") + '">' + (state.fileExplorerShowHidden ? "👁" : "👁‍🗨") + '</button>' +
1371
1371
  '<button class="file-explorer-refresh" id="file-explorer-refresh" title="刷新" aria-label="刷新文件列表">↻</button>' +
1372
1372
  '</div>' +
@@ -1423,12 +1423,10 @@
1423
1423
  '<div class="composer-top-row">' +
1424
1424
  '<div id="todo-progress" class="todo-progress hidden">' +
1425
1425
  '<div class="todo-progress-header" id="todo-progress-toggle">' +
1426
- '<div class="todo-progress-left">' +
1427
- '<span class="todo-progress-spinner"></span>' +
1428
- '<span class="todo-progress-counter" id="todo-progress-counter">0/0</span>' +
1429
- '<span class="todo-progress-task" id="todo-progress-task"></span>' +
1430
- '</div>' +
1431
- '<svg class="todo-progress-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>' +
1426
+ '<span class="todo-progress-spinner" aria-hidden="true"></span>' +
1427
+ '<span class="todo-progress-message" id="todo-progress-message"></span>' +
1428
+ '<span class="todo-progress-status" id="todo-progress-status">执行中</span>' +
1429
+ '<svg class="todo-progress-chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>' +
1432
1430
  '</div>' +
1433
1431
  '<div class="todo-progress-body hidden" id="todo-progress-body">' +
1434
1432
  '<ul class="todo-progress-list" id="todo-progress-list"></ul>' +
@@ -2879,7 +2877,15 @@
2879
2877
  var cwdEl = document.getElementById("file-explorer-cwd");
2880
2878
  if (!cwdEl) return;
2881
2879
  var cwd = session && session.cwd ? session.cwd : getConfigCwd();
2882
- cwdEl.textContent = cwd;
2880
+ // Don't clobber the user's in-progress edit when the input is focused.
2881
+ if (cwdEl.tagName === "INPUT") {
2882
+ if (document.activeElement !== cwdEl) {
2883
+ cwdEl.value = cwd;
2884
+ }
2885
+ } else {
2886
+ cwdEl.textContent = cwd;
2887
+ }
2888
+ cwdEl.title = cwd;
2883
2889
  }
2884
2890
 
2885
2891
  function closeFilePanel() {
@@ -3031,7 +3037,14 @@
3031
3037
  state.fileExplorerTotal = 0;
3032
3038
  explorer.innerHTML = '<div class="file-explorer"><div class="tree-loading" style="padding:12px;color:var(--text-muted);font-size:0.8125rem;">加载中…</div></div>';
3033
3039
  if (cwdEl) {
3034
- cwdEl.textContent = cwd;
3040
+ if (cwdEl.tagName === "INPUT") {
3041
+ // Avoid clobbering in-progress text while the user is typing.
3042
+ if (document.activeElement !== cwdEl) {
3043
+ cwdEl.value = cwd;
3044
+ }
3045
+ } else {
3046
+ cwdEl.textContent = cwd;
3047
+ }
3035
3048
  cwdEl.title = cwd;
3036
3049
  }
3037
3050
  var url = "/api/directory?q=" + encodeURIComponent(cwd) +
@@ -5086,6 +5099,56 @@
5086
5099
  var fileToggleHidden = document.getElementById("file-explorer-toggle-hidden");
5087
5100
  if (fileToggleHidden) fileToggleHidden.addEventListener("click", toggleExplorerHidden);
5088
5101
 
5102
+ // 路径输入框:支持点击修改路径,回车跳转,Esc 撤销。
5103
+ var fileCwdInput = document.getElementById("file-explorer-cwd");
5104
+ if (fileCwdInput && fileCwdInput.tagName === "INPUT") {
5105
+ var lastCommittedCwd = fileCwdInput.value;
5106
+ var normalizeCwdInput = function(raw) {
5107
+ var s = (raw || "").trim();
5108
+ if (!s) return "";
5109
+ // 折叠重复斜杠,去掉尾随斜杠(根目录除外)。
5110
+ s = s.replace(/\/{2,}/g, "/");
5111
+ if (s.length > 1) s = s.replace(/\/+$/, "");
5112
+ return s;
5113
+ };
5114
+ fileCwdInput.addEventListener("focus", function() {
5115
+ lastCommittedCwd = fileCwdInput.value;
5116
+ // Select all on focus so the user can immediately overwrite.
5117
+ setTimeout(function() {
5118
+ try { fileCwdInput.select(); } catch (e) {}
5119
+ }, 0);
5120
+ });
5121
+ fileCwdInput.addEventListener("keydown", function(e) {
5122
+ if (e.key === "Enter") {
5123
+ e.preventDefault();
5124
+ var next = normalizeCwdInput(fileCwdInput.value);
5125
+ if (!next) return;
5126
+ lastCommittedCwd = next;
5127
+ fileCwdInput.value = next;
5128
+ refreshFileExplorer({ cwd: next });
5129
+ fileCwdInput.blur();
5130
+ } else if (e.key === "Escape") {
5131
+ e.preventDefault();
5132
+ fileCwdInput.value = lastCommittedCwd;
5133
+ fileCwdInput.blur();
5134
+ }
5135
+ });
5136
+ fileCwdInput.addEventListener("blur", function() {
5137
+ var next = normalizeCwdInput(fileCwdInput.value);
5138
+ if (!next) {
5139
+ fileCwdInput.value = lastCommittedCwd;
5140
+ return;
5141
+ }
5142
+ if (next === lastCommittedCwd) {
5143
+ fileCwdInput.value = next;
5144
+ return;
5145
+ }
5146
+ lastCommittedCwd = next;
5147
+ fileCwdInput.value = next;
5148
+ refreshFileExplorer({ cwd: next });
5149
+ });
5150
+ }
5151
+
5089
5152
  // File search
5090
5153
  var fileSearchInput = document.getElementById("file-search-input");
5091
5154
  var fileSearchClear = document.getElementById("file-search-clear");
@@ -685,6 +685,40 @@
685
685
  font-weight: 500;
686
686
  }
687
687
 
688
+ /* When rendered as <input> (editable path) keep the same look but reveal
689
+ an editable affordance on hover/focus. */
690
+ input.file-explorer-path {
691
+ background: transparent;
692
+ border: 1px solid transparent;
693
+ border-radius: var(--radius-sm);
694
+ padding: 4px 8px;
695
+ height: 28px;
696
+ line-height: 1.2;
697
+ cursor: text;
698
+ transition: background-color var(--transition-fast),
699
+ border-color var(--transition-fast),
700
+ color var(--transition-fast);
701
+ outline: none;
702
+ text-overflow: ellipsis;
703
+ width: 100%;
704
+ box-sizing: border-box;
705
+ }
706
+ input.file-explorer-path::placeholder {
707
+ color: var(--text-muted);
708
+ opacity: 0.6;
709
+ }
710
+ input.file-explorer-path:hover {
711
+ background: rgba(255, 255, 255, 0.5);
712
+ border-color: var(--border);
713
+ color: var(--text-secondary);
714
+ }
715
+ input.file-explorer-path:focus {
716
+ background: var(--bg-primary);
717
+ border-color: var(--accent);
718
+ color: var(--text-primary);
719
+ text-overflow: clip;
720
+ }
721
+
688
722
  .file-explorer-actions { display: flex; gap: 4px; margin-left: auto; flex-shrink: 0; }
689
723
 
690
724
  .file-explorer-refresh {
@@ -10473,7 +10507,10 @@
10473
10507
  }
10474
10508
 
10475
10509
  .file-preview-modal {
10476
- width: min(90vw, calc(100vw - 380px));
10510
+ /* 桌面端:留出侧边栏空间,但保证最小宽度,避免在窄视口上塌成一条缝。
10511
+ 之前是 min(90vw, calc(100vw - 380px)),当 100vw < 380px 时整个值为负,
10512
+ 元素直接被收成 0 宽。这里用 max() 兜底一个最小宽度。 */
10513
+ width: min(90vw, max(640px, calc(100vw - 380px)));
10477
10514
  max-width: 1000px;
10478
10515
  height: 80vh;
10479
10516
  max-height: 85vh;
@@ -10492,6 +10529,65 @@
10492
10529
  to { opacity: 1; transform: translateY(0) scale(1); }
10493
10530
  }
10494
10531
 
10532
+ /* 移动端(含竖屏手机):铺满整个视口,去掉圆角和边框,
10533
+ 使用 dvh 兼容浏览器地址栏占用。 */
10534
+ @media (max-width: 768px) {
10535
+ .file-preview-overlay {
10536
+ padding: 0;
10537
+ align-items: stretch;
10538
+ justify-content: stretch;
10539
+ }
10540
+ .file-preview-modal {
10541
+ width: 100vw;
10542
+ max-width: 100vw;
10543
+ height: 100vh;
10544
+ height: 100dvh;
10545
+ max-height: 100vh;
10546
+ max-height: 100dvh;
10547
+ border-radius: 0;
10548
+ border: none;
10549
+ box-shadow: none;
10550
+ animation: fade-in 0.18s ease;
10551
+ }
10552
+ .file-preview-header {
10553
+ padding: 10px 12px;
10554
+ gap: 8px;
10555
+ /* 给安全区让位,例如带刘海的设备 */
10556
+ padding-top: max(10px, env(safe-area-inset-top));
10557
+ padding-left: max(12px, env(safe-area-inset-left));
10558
+ padding-right: max(12px, env(safe-area-inset-right));
10559
+ }
10560
+ .file-preview-title {
10561
+ font-size: 0.875rem;
10562
+ gap: 6px;
10563
+ min-width: 0;
10564
+ flex: 1;
10565
+ }
10566
+ .file-preview-filename {
10567
+ max-width: 100%;
10568
+ }
10569
+ /* 路径在窄屏上极易抢空间,直接隐藏,hover/长按文件名仍可看到完整路径。 */
10570
+ .file-preview-path {
10571
+ display: none;
10572
+ }
10573
+ .file-preview-toolbar {
10574
+ gap: 4px;
10575
+ flex-shrink: 0;
10576
+ }
10577
+ .file-preview-toolbar-btn {
10578
+ padding: 4px 6px;
10579
+ font-size: 0.75rem;
10580
+ }
10581
+ .file-preview-close {
10582
+ font-size: 1.375rem;
10583
+ padding: 6px 10px;
10584
+ }
10585
+ /* 底部安全区(小白条 / 圆角) */
10586
+ .file-preview-body {
10587
+ padding-bottom: env(safe-area-inset-bottom);
10588
+ }
10589
+ }
10590
+
10495
10591
  .file-preview-header {
10496
10592
  display: flex;
10497
10593
  align-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "1.21.18",
3
+ "version": "1.22.0",
4
4
  "description": "A web terminal for local CLI tools like Claude.",
5
5
  "type": "module",
6
6
  "bin": {