mock-service-cli 4.11.0 → 4.12.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.
@@ -29,7 +29,7 @@
29
29
  }
30
30
 
31
31
  .container {
32
- max-width: 1200px;
32
+ max-width: 1400px;
33
33
  margin: 0 auto;
34
34
  display: flex;
35
35
  flex-direction: column;
@@ -95,26 +95,31 @@
95
95
  }
96
96
 
97
97
  .toolbar {
98
- padding: 10px 12px;
98
+ padding: 5px 6px;
99
99
  border-bottom: 1px solid #eee;
100
100
  display: flex;
101
- gap: 8px;
101
+ gap: 4px;
102
102
  align-items: center;
103
103
  flex-wrap: wrap;
104
104
  flex-shrink: 0;
105
105
  }
106
106
 
107
+ /* Keep the dynamic counter from re-wrapping the toolbar while it updates. */
107
108
  .stats-info {
108
109
  font-size: 12px;
109
110
  color: #666;
110
- padding: 4px 8px;
111
+ padding: 4px 4px;
111
112
  background: #f8f8f8;
112
113
  border-radius: 4px;
114
+ min-width: 168px;
115
+ text-align: center;
116
+ white-space: nowrap;
117
+ font-variant-numeric: tabular-nums;
113
118
  }
114
119
 
115
120
  .search-box {
116
- flex: 1;
117
- min-width: 150px;
121
+ flex: 1 1 120px;
122
+ min-width: 120px;
118
123
  }
119
124
 
120
125
  .search-box input {
@@ -138,7 +143,7 @@
138
143
  }
139
144
 
140
145
  .sort-select {
141
- padding: 6px 10px;
146
+ padding: 6px 8px;
142
147
  border: 1px solid #ddd;
143
148
  border-radius: 4px;
144
149
  font-size: 12px;
@@ -152,7 +157,7 @@
152
157
  }
153
158
 
154
159
  .sort-order-btn {
155
- padding: 6px 10px;
160
+ padding: 6px 4px;
156
161
  background: #f0f0f0;
157
162
  border: none;
158
163
  border-radius: 4px;
@@ -166,7 +171,8 @@
166
171
  }
167
172
 
168
173
  .toolbar-action-btn {
169
- padding: 6px 10px;
174
+ padding: 6px 4px;
175
+ white-space: nowrap;
170
176
  background: #f0f0f0;
171
177
  border: none;
172
178
  border-radius: 4px;
@@ -210,7 +216,8 @@
210
216
  }
211
217
 
212
218
  .back-btn {
213
- padding: 6px 12px;
219
+ padding: 6px 4px;
220
+ white-space: nowrap;
214
221
  background: #f0f0f0;
215
222
  border: none;
216
223
  border-radius: 4px;
@@ -239,7 +246,8 @@
239
246
  }
240
247
 
241
248
  .view-btn {
242
- padding: 4px 10px;
249
+ padding: 4px 4px;
250
+ white-space: nowrap;
243
251
  background: transparent;
244
252
  border: none;
245
253
  border-radius: 3px;
@@ -254,7 +262,7 @@
254
262
  }
255
263
 
256
264
  .refresh-btn {
257
- padding: 6px 10px;
265
+ padding: 4px 4px;
258
266
  background: #f0f0f0;
259
267
  border: none;
260
268
  border-radius: 4px;
@@ -268,7 +276,7 @@
268
276
  }
269
277
 
270
278
  .toggle-hidden-btn {
271
- padding: 6px 10px;
279
+ padding: 4px 4px;
272
280
  background: #f0f0f0;
273
281
  border: none;
274
282
  border-radius: 4px;
@@ -302,7 +310,7 @@
302
310
  }
303
311
 
304
312
  .context-menu-item {
305
- padding: 10px 16px;
313
+ padding: 5px 8px;
306
314
  cursor: pointer;
307
315
  font-size: 14px;
308
316
  color: #333;
@@ -379,8 +387,8 @@
379
387
  display: flex;
380
388
  flex-direction: column;
381
389
  align-items: center;
382
- padding: 10px 8px;
383
- border-radius: 6px;
390
+ padding: 5px 4px;
391
+ border-radius: 4px;
384
392
  cursor: pointer;
385
393
  transition: background-color 0.2s;
386
394
  }
@@ -1052,12 +1060,7 @@
1052
1060
  >
1053
1061
  压缩选中
1054
1062
  </button>
1055
- <button
1056
- class="toggle-hidden-btn"
1057
- id="toggleHiddenBtn"
1058
- onclick="toggleHiddenFiles()"
1059
- title="显示/隐藏隐藏文件"
1060
- >
1063
+ <button class="toggle-hidden-btn" id="toggleHiddenBtn" onclick="toggleHiddenFiles()" title="显示隐藏文件">
1061
1064
  👁️
1062
1065
  </button>
1063
1066
  <button
@@ -1083,8 +1086,8 @@
1083
1086
  </button>
1084
1087
  </div>
1085
1088
  <div class="view-toggle">
1086
- <button class="view-btn active" id="gridViewBtn" onclick="setView('grid')">网格</button>
1087
- <button class="view-btn" id="listViewBtn" onclick="setView('list')">列表</button>
1089
+ <button class="view-btn" id="gridViewBtn" onclick="setView('grid')">网格</button>
1090
+ <button class="view-btn active" id="listViewBtn" onclick="setView('list')">列表</button>
1088
1091
  </div>
1089
1092
  </div>
1090
1093
  <div class="file-grid" id="fileGrid"></div>
@@ -1123,14 +1126,18 @@
1123
1126
  <div class="context-menu-item edit-only edit-flex" id="ctxExtract" onclick="handleContextMenuAction('extract')">
1124
1127
  📦 解压到当前目录
1125
1128
  </div>
1126
- <div class="context-menu-item edit-only edit-flex" id="ctxArchivePreview" onclick="handleContextMenuAction('archivePreview')">
1129
+ <div
1130
+ class="context-menu-item edit-only edit-flex"
1131
+ id="ctxArchivePreview"
1132
+ onclick="handleContextMenuAction('archivePreview')"
1133
+ >
1127
1134
  🔎 查看压缩包
1128
1135
  </div>
1129
1136
  </div>
1130
1137
 
1131
1138
  <script>
1132
1139
  let currentPath = '/';
1133
- let currentView = 'grid';
1140
+ let currentView = 'list';
1134
1141
  let currentFiles = [];
1135
1142
  let allFiles = [];
1136
1143
  let searchQuery = '';
@@ -1418,7 +1425,12 @@
1418
1425
  function getStoredExplorerPath() {
1419
1426
  try {
1420
1427
  const stored = JSON.parse(sessionStorage.getItem(EXPLORER_PATH_STORAGE_KEY));
1421
- if (stored && stored.rootId === explorerRootId && typeof stored.path === 'string' && stored.path.startsWith('/')) {
1428
+ if (
1429
+ stored &&
1430
+ stored.rootId === explorerRootId &&
1431
+ typeof stored.path === 'string' &&
1432
+ stored.path.startsWith('/')
1433
+ ) {
1422
1434
  return stored.path;
1423
1435
  }
1424
1436
  } catch (error) {
@@ -1558,9 +1570,17 @@
1558
1570
  hideContextMenu();
1559
1571
  }
1560
1572
 
1573
+ function isSameExplorerPath(left, right) {
1574
+ const normalize = value => String(value || '/').replace(/\/+$/, '') || '/';
1575
+ return normalize(left) === normalize(right);
1576
+ }
1577
+
1561
1578
  async function loadDirectory(path, { fallbackToRoot = false } = {}) {
1562
1579
  const fileGrid = document.getElementById('fileGrid');
1563
1580
  const oldCurrentPath = currentPath;
1581
+ // Refresh buttons and post-operation reloads revisit the same directory:
1582
+ // keep the active search instead of silently resetting the filter.
1583
+ const keepSearch = isSameExplorerPath(path, currentPath);
1564
1584
  const requestId = ++directoryRequestId;
1565
1585
 
1566
1586
  if (directoryRequestController) {
@@ -1592,10 +1612,15 @@
1592
1612
  storeExplorerPath(currentPath);
1593
1613
  allFiles = data.files || [];
1594
1614
 
1595
- if (document.getElementById('searchInput')) {
1596
- document.getElementById('searchInput').value = '';
1615
+ const searchInput = document.getElementById('searchInput');
1616
+ if (!keepSearch) {
1617
+ if (searchInput) searchInput.value = '';
1618
+ searchQuery = '';
1619
+ } else if (searchInput) {
1620
+ // A refresh may land inside the search debounce window; resync so the
1621
+ // filtered view matches the visible query immediately.
1622
+ searchQuery = searchInput.value;
1597
1623
  }
1598
- searchQuery = '';
1599
1624
 
1600
1625
  renderBreadcrumb(data.currentPath, data.parentPath);
1601
1626
  processAndRenderFiles();
@@ -1700,7 +1725,7 @@
1700
1725
  if (showHiddenFiles) {
1701
1726
  btn.classList.add('active');
1702
1727
  btn.innerHTML = '👁️';
1703
- btn.title = '隐藏隐藏文件';
1728
+ btn.title = '不再显示隐藏文件';
1704
1729
  } else {
1705
1730
  btn.classList.remove('active');
1706
1731
  btn.innerHTML = '👁️‍🗨️';
@@ -1767,7 +1792,9 @@
1767
1792
 
1768
1793
  function isArchiveFile(filePath) {
1769
1794
  const lowerPath = String(filePath || '').toLowerCase();
1770
- return archiveCapabilities.readExtensions.some(extension => lowerPath.endsWith(`.${String(extension).toLowerCase()}`));
1795
+ return archiveCapabilities.readExtensions.some(extension =>
1796
+ lowerPath.endsWith(`.${String(extension).toLowerCase()}`)
1797
+ );
1771
1798
  }
1772
1799
 
1773
1800
  async function createArchiveFromSelection(sourceOverride) {
@@ -1776,7 +1803,13 @@
1776
1803
  showToast('请先选择要压缩的文件或文件夹');
1777
1804
  return;
1778
1805
  }
1779
- const defaultName = sources.length === 1 ? sources[0].split('/').pop().replace(/\.[^.]+$/, '') : 'archive';
1806
+ const defaultName =
1807
+ sources.length === 1
1808
+ ? sources[0]
1809
+ .split('/')
1810
+ .pop()
1811
+ .replace(/\.[^.]+$/, '')
1812
+ : 'archive';
1780
1813
  const name = window.prompt('压缩包名称', defaultName);
1781
1814
  if (name === null || !name.trim()) return;
1782
1815
  const formats = archiveCapabilities.createFormats;
@@ -1800,7 +1833,9 @@
1800
1833
  }
1801
1834
 
1802
1835
  async function extractArchive(filePath) {
1803
- const confirmed = window.confirm(`将 “${filePath.split('/').pop()}” 解压到当前目录吗?已有同名文件将导致整个操作失败。`);
1836
+ const confirmed = window.confirm(
1837
+ `将 “${filePath.split('/').pop()}” 解压到当前目录吗?已有同名文件将导致整个操作失败。`
1838
+ );
1804
1839
  if (!confirmed) return;
1805
1840
  await startArchiveJob({ operation: 'extract', path: filePath, destinationPath: currentPath });
1806
1841
  }
@@ -1889,8 +1924,16 @@
1889
1924
  <div class="binary-info">${entries.length} 项 · 解压后 ${formatSize(preview.totalSize || 0)} · 包内数据 ${formatSize(preview.totalPackedSize || 0)}</div>
1890
1925
  <div class="text-preview">${entries
1891
1926
  .map(entry => {
1892
- const depth = entry.path.split('/').length - 1;
1893
- const label = `${entry.isDirectory ? '📁' : '📄'} ${entry.path.split('/').pop()}${entry.isDirectory ? '/' : ` (${formatSize(entry.size || 0)})`}`;
1927
+ const normalizedPath = String(entry.path || '').replace(/\/+$/, '');
1928
+ const segments = normalizedPath.split('/');
1929
+ const depth = segments.length - 1;
1930
+ const icon = entry.isSymbolicLink ? '🔗' : entry.isDirectory ? '📁' : '📄';
1931
+ const suffix = entry.isDirectory
1932
+ ? '/'
1933
+ : entry.isSymbolicLink
1934
+ ? ' (链接)'
1935
+ : ` (${formatSize(entry.size || 0)})`;
1936
+ const label = `${icon} ${segments.pop()}${suffix}`;
1894
1937
  return `<div style="padding-left:${depth * 16}px">${escapeHtml(label)}</div>`;
1895
1938
  })
1896
1939
  .join('')}</div>