@wendongfly/myhi 1.3.197 → 1.3.199
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.
- package/dist/chat.html +259 -28
- package/dist/index.html +165 -7
- package/dist/index.js +1 -1
- package/dist/index.min.js +172 -170
- package/dist/lib/attn.js +46 -0
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
<title>myhi 会话</title>
|
|
12
12
|
<script src="/lib/machine.js" data-session></script>
|
|
13
13
|
<script src="/lib/prefs.js"></script>
|
|
14
|
+
<script src="/lib/attn.js"></script>
|
|
14
15
|
<script src="/sio-client/socket.io.min.js"></script>
|
|
15
16
|
<script src="/theme.js"></script>
|
|
16
17
|
<script>
|
|
@@ -24,6 +25,9 @@
|
|
|
24
25
|
if(em==='1') r.classList.add('embed');
|
|
25
26
|
// 首页电脑端工作台右侧嵌入:保留本页顶栏,左侧已有任务列表 → 藏掉分屏/切换/返回;
|
|
26
27
|
// 页面里的链接(如「首页 ⚙ 设置」)在整个窗口打开,别在右侧小框里再套一个首页
|
|
28
|
+
// 手机(触屏且窄屏,平板横屏 >768px 按电脑处理)且未关「移动端精简」→ 精简布局
|
|
29
|
+
var cs={};try{cs=JSON.parse(localStorage.getItem('myhi_chat_settings')||'{}')||{}}catch(e){}
|
|
30
|
+
if(!em&&cs.mobileCompact!==false&&matchMedia('(pointer: coarse) and (max-width: 768px)').matches) r.classList.add('m');
|
|
27
31
|
if(em==='ws'){ r.classList.add('embed-ws'); var bs=document.createElement('base'); bs.target='_top'; document.head.appendChild(bs); }
|
|
28
32
|
}catch(e){}})();
|
|
29
33
|
</script>
|
|
@@ -77,6 +81,32 @@
|
|
|
77
81
|
.top-btn:hover { background: var(--surface2); color: var(--text); }
|
|
78
82
|
.top-btn:active { transform: scale(0.92); }
|
|
79
83
|
|
|
84
|
+
/* ── 移动端精简(html.m):顶栏只留 ← / ●任务名▾ / ⋯,状态行收进 ⋯ ── */
|
|
85
|
+
#title-row { display: flex; align-items: center; gap: 0.35rem; min-width: 0; }
|
|
86
|
+
#m-dot, #m-back, #m-more, #m-ro { display: none; }
|
|
87
|
+
html.m #m-back, html.m #m-more { display: inline-flex; }
|
|
88
|
+
html.m #m-dot { display: inline-block; }
|
|
89
|
+
html.m #m-ro.show { display: inline-flex; }
|
|
90
|
+
html.m .top-hide-m, html.m #status-bar, html.m #session-cwd { display: none !important; }
|
|
91
|
+
html.m #title-group { cursor: pointer; }
|
|
92
|
+
html.m #session-title::after { content: ' ▾'; color: var(--muted); font-size: 0.7rem; font-weight: 400; }
|
|
93
|
+
html.m #ctx-chip:not(.hi) { display: none !important; }
|
|
94
|
+
html.m #sk-builtin-skills, html.m #sk-custom-skills { display: none !important; }
|
|
95
|
+
html.m #top-bar { transition: margin-top 0.2s ease; }
|
|
96
|
+
/* 安全区只在「添加到主屏幕」全屏运行时才需要;普通浏览器标签页上面已有地址栏,
|
|
97
|
+
部分国产浏览器仍报状态栏高度 → 顶栏上方白空一行,这里不留 */
|
|
98
|
+
@media (display-mode: browser) {
|
|
99
|
+
#top-bar { padding-top: 0.5rem; }
|
|
100
|
+
#m-toast { top: 3.2rem; }
|
|
101
|
+
}
|
|
102
|
+
#m-more { position: relative; font-size: 1.1rem; letter-spacing: 1px; }
|
|
103
|
+
#m-more.dot::after { content: ''; position: absolute; top: 6px; right: 5px; width: 7px; height: 7px; border-radius: 50%; background: var(--red); }
|
|
104
|
+
#m-ro { font-size: 0.68rem; color: var(--muted); border: 1px solid var(--border); border-radius: 10px; padding: 0.1rem 0.45rem; white-space: nowrap; flex-shrink: 0; cursor: pointer; }
|
|
105
|
+
/* 其他任务完成 / 等你回复的提醒条 */
|
|
106
|
+
#m-toast { position: fixed; left: 0.6rem; right: 0.6rem; top: calc(3.2rem + env(safe-area-inset-top)); z-index: 110; background: var(--surface2); color: var(--text); border: 1px solid var(--border); border-left: 4px solid var(--green); border-radius: 10px; padding: 0.6rem 0.8rem; font-size: 0.82rem; box-shadow: 0 6px 20px rgba(0,0,0,0.35); display: none; cursor: pointer; }
|
|
107
|
+
#m-toast.show { display: block; }
|
|
108
|
+
#m-toast .sub { font-size: 0.72rem; color: var(--muted); margin-top: 0.15rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
109
|
+
|
|
80
110
|
/* ── 状态栏 ─────────────────────────────── */
|
|
81
111
|
#status-bar { display: flex; align-items: center; gap: 0.6rem; padding: 0.3rem 0.75rem; background: var(--bg); border-bottom: 1px solid var(--surface2); font-size: 0.72rem; overflow-x: auto; flex-shrink: 0; scrollbar-width: none; }
|
|
82
112
|
#status-bar::-webkit-scrollbar { display: none; }
|
|
@@ -420,7 +450,10 @@
|
|
|
420
450
|
#fedit-ta:focus { border-color: var(--purple); }
|
|
421
451
|
/* 预览复用记忆面板的 .md 渲染样式,只解开它自带的 max-height/隐藏 */
|
|
422
452
|
#fedit-preview { display: none; max-height: none; flex: 1; min-height: 0; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); }
|
|
453
|
+
#fedit-preview.html { padding: 0; overflow: hidden; background: #fff; }
|
|
454
|
+
#fedit-preview.html iframe { width: 100%; height: 100%; border: 0; display: block; background: #fff; }
|
|
423
455
|
.fedit-tab { flex-shrink: 0; }
|
|
456
|
+
#fedit-sheet .fp-btn { white-space: nowrap; }
|
|
424
457
|
.fedit-tab.on { border-color: var(--purple); background: var(--purple); color: #fff; }
|
|
425
458
|
.fp-btn-warn { background: var(--yellow2); border-color: #d2992280; }
|
|
426
459
|
.fp-btn-warn:active { background: var(--yellow2); }
|
|
@@ -651,21 +684,27 @@
|
|
|
651
684
|
|
|
652
685
|
<div id="top-bar">
|
|
653
686
|
<button id="grid-btn" class="top-btn" onclick="location.href='/grid'" title="分屏工作台(多任务并排)" style="font-size:1.05rem;padding:0 0.35rem;color:var(--blue2)">▦</button>
|
|
654
|
-
<
|
|
655
|
-
<
|
|
687
|
+
<button id="m-back" class="top-btn" onclick="goHome()" title="首页">
|
|
688
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
|
689
|
+
</button>
|
|
690
|
+
<div id="title-group" onclick="if(document.documentElement.classList.contains('m'))openSwitchSheet()">
|
|
691
|
+
<div id="title-row"><span id="m-dot" class="sb-dot idle"></span><div id="session-title">加载中...</div></div>
|
|
656
692
|
<div id="session-cwd"></div>
|
|
657
693
|
</div>
|
|
658
|
-
<
|
|
659
|
-
<button class="top-btn" onclick="
|
|
694
|
+
<span id="m-ro" onclick="toggleControl()"></span>
|
|
695
|
+
<button class="top-btn top-hide-m" onclick="openChatHelp()" title="使用说明" style="font-size:0.7rem;color:var(--muted)">?</button>
|
|
696
|
+
<button class="top-btn top-hide-m" onclick="openSettings()" title="设置">
|
|
660
697
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 01-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg>
|
|
661
698
|
</button>
|
|
662
699
|
<button class="top-btn" id="ctx-chip" onclick="openCtxSheet()" title="会话数据:上下文水位 / 成本 / token 明细" style="display:none;width:auto;padding:0 0.5rem;white-space:nowrap;font-size:0.7rem;color:var(--muted)">◈ --</button>
|
|
663
|
-
<button class="top-btn" onclick="openFilePanel()" title="文件" style="font-size:0.7rem;color:var(--muted)">文件</button>
|
|
664
|
-
<button class="top-btn" onclick="openSwitchSheet()" title="切换会话" style="font-size:0.7rem;color:var(--muted)">切换</button>
|
|
665
|
-
<button class="top-btn" onclick="goBack()" title="返回">
|
|
700
|
+
<button class="top-btn top-hide-m" onclick="openFilePanel()" title="文件" style="font-size:0.7rem;color:var(--muted)">文件</button>
|
|
701
|
+
<button class="top-btn top-hide-m" onclick="openSwitchSheet()" title="切换会话" style="font-size:0.7rem;color:var(--muted)">切换</button>
|
|
702
|
+
<button class="top-btn top-hide-m" onclick="goBack()" title="返回">
|
|
666
703
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
|
667
704
|
</button>
|
|
705
|
+
<button id="m-more" class="top-btn" onclick="openMobileMore()" title="更多">⋯</button>
|
|
668
706
|
</div>
|
|
707
|
+
<div id="m-toast"></div>
|
|
669
708
|
|
|
670
709
|
<div id="status-bar">
|
|
671
710
|
<span class="sb-item" id="work-status"><span class="sb-dot idle"></span> 空闲</span>
|
|
@@ -770,7 +809,7 @@
|
|
|
770
809
|
<button class="sk sk-claude" data-sk="followup" onclick="openFollowUpSheet()" style="color:var(--blue2)">🔄 跟进</button>
|
|
771
810
|
<button class="sk sk-claude" data-sk="git" onclick="openGitSheet()" style="color:var(--green)">提交</button>
|
|
772
811
|
<button class="sk sk-claude" data-sk="memory" onclick="showMemory()">记忆</button>
|
|
773
|
-
<button class="sk sk-claude" data-sk="skills" onclick="
|
|
812
|
+
<button class="sk sk-claude" data-sk="skills" onclick="skillBtnTap()" style="color:var(--purple2)">技能</button>
|
|
774
813
|
<span id="sk-builtin-skills" data-sk="skills"></span>
|
|
775
814
|
<span id="sk-custom-skills" data-sk="skills"></span>
|
|
776
815
|
</div>
|
|
@@ -824,6 +863,7 @@
|
|
|
824
863
|
<div class="set-line"><span>思考过程</span><div id="seg-think" class="seg-row"><button class="seg" data-v="hide">隐藏</button><button class="seg" data-v="fold">折叠</button><button class="seg" data-v="open">展开</button></div></div>
|
|
825
864
|
<div class="set-line"><span>工具调用</span><div id="seg-tools" class="seg-row"><button class="seg" data-v="fold">折叠</button><button class="seg" data-v="open">展开</button></div></div>
|
|
826
865
|
<div class="set-line"><span>工具输出<small>AI 执行命令/读文件的原始结果</small></span><div id="seg-toolout" class="seg-row"><button class="seg" data-v="hide">隐藏</button><button class="seg" data-v="clip">前8行</button><button class="seg" data-v="all">全部</button></div></div>
|
|
866
|
+
<div class="set-line"><span>手机布局<small>仅手机生效:精简只留任务名、状态与切换</small></span><div id="seg-mobile" class="seg-row"><button class="seg" data-v="on">精简</button><button class="seg" data-v="off">完整</button></div></div>
|
|
827
867
|
<label class="setting-toggle" id="row-parse"><span>把终端里的 Claude 输出整理成聊天样式</span><input type="checkbox" id="set-parse" checked></label>
|
|
828
868
|
</div>
|
|
829
869
|
<div class="setting-group" data-stab="chat" style="display:none">
|
|
@@ -1140,10 +1180,13 @@
|
|
|
1140
1180
|
<div class="action-sheet-backdrop" onclick="closeFileEditor()"></div>
|
|
1141
1181
|
<div class="action-sheet-box" style="height:92vh;max-height:92vh;display:flex;flex-direction:column">
|
|
1142
1182
|
<div class="action-sheet-title" style="display:flex;align-items:center;gap:0.5rem">
|
|
1143
|
-
<span style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"
|
|
1183
|
+
<span style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"><span id="fedit-icon">✏️</span> <span id="fedit-title">文件</span></span>
|
|
1144
1184
|
<span id="fedit-state" style="font-size:0.64rem;color:var(--muted);flex-shrink:0;font-weight:400"></span>
|
|
1145
1185
|
</div>
|
|
1146
|
-
<div
|
|
1186
|
+
<div style="display:flex;align-items:flex-start;gap:0.4rem;padding:0 0.2rem 0.4rem">
|
|
1187
|
+
<div id="fedit-path" style="flex:1;min-width:0;font-size:0.68rem;color:var(--muted);word-break:break-all;font-family:'SF Mono',Consolas,monospace" title="文件所在位置"></div>
|
|
1188
|
+
<button class="fp-btn" onclick="feditCopyPath(this)" style="flex-shrink:0;font-size:0.66rem;padding:0.15rem 0.45rem" title="复制完整路径">📋 复制路径</button>
|
|
1189
|
+
</div>
|
|
1147
1190
|
<div style="flex:1;min-height:0;display:flex;flex-direction:column;gap:0.4rem;padding:0 0.2rem">
|
|
1148
1191
|
<div id="fedit-loading" style="flex:1;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:0.82rem">加载中...</div>
|
|
1149
1192
|
<textarea id="fedit-ta" spellcheck="false"></textarea>
|
|
@@ -1152,6 +1195,7 @@
|
|
|
1152
1195
|
<div style="display:flex;gap:0.4rem;padding:0.5rem 0.2rem 0;align-items:center">
|
|
1153
1196
|
<button class="fp-btn fedit-tab" id="fedit-tab-edit" onclick="feditSetMode('edit')">✏️ 编辑</button>
|
|
1154
1197
|
<button class="fp-btn fedit-tab" id="fedit-tab-preview" onclick="feditSetMode('preview')" style="display:none">👁 预览</button>
|
|
1198
|
+
<button class="fp-btn" id="fedit-newtab" onclick="feditOpenTab()" style="display:none" title="在浏览器新标签页里全屏查看(已保存的版本)">↗ 全屏</button>
|
|
1155
1199
|
<span style="flex:1"></span>
|
|
1156
1200
|
<button class="fp-btn" onclick="feditReload()" title="放弃本地修改,重新读磁盘最新内容">🔄 重读</button>
|
|
1157
1201
|
<button class="fp-btn" onclick="closeFileEditor()">关闭</button>
|
|
@@ -1167,7 +1211,7 @@
|
|
|
1167
1211
|
<div id="cmd-sheet" class="action-sheet">
|
|
1168
1212
|
<div class="action-sheet-backdrop" onclick="closeCmdSheet()"></div>
|
|
1169
1213
|
<div class="action-sheet-box" style="max-height:75vh;display:flex;flex-direction:column">
|
|
1170
|
-
<div class="action-sheet-title">自定义命令</div>
|
|
1214
|
+
<div class="action-sheet-title" id="cmd-sheet-title">自定义命令</div>
|
|
1171
1215
|
<div style="padding:0.3rem 0.2rem">
|
|
1172
1216
|
<input id="cmd-filter" class="slash-inp" placeholder="搜索命令..." autocomplete="off">
|
|
1173
1217
|
</div>
|
|
@@ -1739,6 +1783,7 @@
|
|
|
1739
1783
|
if (h.start > last) frag.appendChild(document.createTextNode(s.slice(last, h.start)));
|
|
1740
1784
|
const a = document.createElement('span');
|
|
1741
1785
|
a.className = 'file-link';
|
|
1786
|
+
a.title = /\.(html?|md|markdown)$/i.test(h.text) ? '点击查看(可切到编辑)' : '点击查看 / 编辑';
|
|
1742
1787
|
a.textContent = h.text;
|
|
1743
1788
|
a.dataset.path = h.text;
|
|
1744
1789
|
frag.appendChild(a);
|
|
@@ -2798,6 +2843,7 @@
|
|
|
2798
2843
|
};
|
|
2799
2844
|
const s = STATES[state] || STATES.idle;
|
|
2800
2845
|
el.innerHTML = `<span class="sb-dot ${s.dot}"></span> ${s.text}`;
|
|
2846
|
+
const md = document.getElementById('m-dot'); if (md) { md.className = 'sb-dot ' + s.dot; md.title = s.text; }
|
|
2801
2847
|
// 回归 idle 由 result / agent:busy false / session-exit 驱动,
|
|
2802
2848
|
// 不做定时兜底——长工具调用期间兜底会让取消按钮提前消失。
|
|
2803
2849
|
if (currentSession?.mode === 'agent') {
|
|
@@ -3442,12 +3488,13 @@
|
|
|
3442
3488
|
if (tokens > 0) _lastCtxTokens = tokens;
|
|
3443
3489
|
const chip = document.getElementById('ctx-chip');
|
|
3444
3490
|
if (!chip) return;
|
|
3445
|
-
if (!tokens || tokens <= 0) { chip.style.display = 'none'; return; }
|
|
3491
|
+
if (!tokens || tokens <= 0) { chip.style.display = 'none'; chip.classList.remove('hi'); return; }
|
|
3446
3492
|
const limit = ctxLimit(tokens);
|
|
3447
3493
|
const pct = Math.min(100, Math.round(tokens / limit * 100));
|
|
3448
3494
|
chip.style.display = '';
|
|
3449
3495
|
chip.textContent = `◈ ${pct}%`;
|
|
3450
3496
|
chip.style.color = pct >= 90 ? 'var(--red)' : pct >= 75 ? 'var(--yellow)' : 'var(--muted)';
|
|
3497
|
+
chip.classList.toggle('hi', pct >= 75); // 手机精简布局只在偏高时才露出来
|
|
3451
3498
|
// 压缩快捷按钮同步高亮(agent 栏是 doSlashCmd('/compact'),PTY 栏是 doCompact())
|
|
3452
3499
|
for (const sel of [
|
|
3453
3500
|
'#sk-claude-agent button[onclick*="/compact"]',
|
|
@@ -3938,6 +3985,9 @@
|
|
|
3938
3985
|
document.querySelectorAll('.sk').forEach(b => b.disabled = !canTakeControl());
|
|
3939
3986
|
}
|
|
3940
3987
|
updateShortcutBar();
|
|
3988
|
+
// 手机顶栏:没控制权时露出一个小标(只读 / 获取控制 / X 控制中),点了等同控制徽标
|
|
3989
|
+
const ro = document.getElementById('m-ro');
|
|
3990
|
+
if (ro) { ro.textContent = controlling ? '' : badge.textContent; ro.classList.toggle('show', !controlling); }
|
|
3941
3991
|
}
|
|
3942
3992
|
|
|
3943
3993
|
// ── 设置面板 ──────────────────────────────────
|
|
@@ -4205,14 +4255,19 @@
|
|
|
4205
4255
|
const sheet = document.getElementById('fedit-sheet');
|
|
4206
4256
|
sheet.classList.add('open');
|
|
4207
4257
|
document.getElementById('fedit-title').textContent = rel.split('/').pop();
|
|
4208
|
-
document.getElementById('fedit-path').textContent = rel;
|
|
4258
|
+
document.getElementById('fedit-path').textContent = feditAbs(rel);
|
|
4209
4259
|
document.getElementById('fedit-loading').style.display = 'flex';
|
|
4210
4260
|
document.getElementById('fedit-loading').textContent = '加载中...';
|
|
4211
4261
|
document.getElementById('fedit-ta').style.display = 'none';
|
|
4212
4262
|
document.getElementById('fedit-preview').style.display = 'none';
|
|
4213
4263
|
feditSetState('');
|
|
4214
4264
|
try {
|
|
4215
|
-
|
|
4265
|
+
let r = await fetch(`/api/files/${SESSION_ID}/content?path=${encodeURIComponent(rel)}`);
|
|
4266
|
+
// AI 常只写文件名(不带目录):根目录没有就在任务目录里按名字找,唯一命中就打开它
|
|
4267
|
+
if (r.status === 404 && !rel.includes('/')) {
|
|
4268
|
+
const hit = await feditFindByName(rel);
|
|
4269
|
+
if (hit) { r = await fetch(`/api/files/${SESSION_ID}/content?path=${encodeURIComponent(hit)}`); document.getElementById('fedit-path').textContent = feditAbs(hit); }
|
|
4270
|
+
}
|
|
4216
4271
|
const d = await r.json().catch(() => ({}));
|
|
4217
4272
|
if (!r.ok || !d.ok) {
|
|
4218
4273
|
const map = { 404: '文件不存在(可能还没生成,或路径不对)', 403: '路径越界(不在会话目录内)', 413: '文件超过 2MB,请用下载' };
|
|
@@ -4220,26 +4275,82 @@
|
|
|
4220
4275
|
sheet.classList.remove('open');
|
|
4221
4276
|
return;
|
|
4222
4277
|
}
|
|
4223
|
-
|
|
4278
|
+
const html = /\.html?$/i.test(d.name || d.path || '');
|
|
4279
|
+
_fedit = { path: d.path, name: d.name, mtime: d.mtime, md: !!d.md, html, mode: 'edit', loaded: d.content, dirty: false };
|
|
4280
|
+
document.getElementById('fedit-path').textContent = feditAbs(d.path);
|
|
4224
4281
|
document.getElementById('fedit-ta').value = d.content;
|
|
4225
4282
|
document.getElementById('fedit-loading').style.display = 'none';
|
|
4226
|
-
document.getElementById('fedit-tab-preview').style.display = _fedit.md ? '' : 'none';
|
|
4227
|
-
|
|
4283
|
+
document.getElementById('fedit-tab-preview').style.display = (_fedit.md || html) ? '' : 'none';
|
|
4284
|
+
document.getElementById('fedit-newtab').style.display = html ? '' : 'none';
|
|
4285
|
+
// 文档类(md / html)默认「看」,要改再点 ✏️ 编辑
|
|
4286
|
+
feditSetMode(_fedit.md || html ? 'preview' : 'edit');
|
|
4228
4287
|
} catch (e) {
|
|
4229
4288
|
addStatusMessage('打开出错: ' + e.message);
|
|
4230
4289
|
sheet.classList.remove('open');
|
|
4231
4290
|
}
|
|
4232
4291
|
};
|
|
4233
4292
|
|
|
4293
|
+
// 完整路径(任务目录 + 相对路径),方便知道文件在哪、复制给别的工具
|
|
4294
|
+
function feditAbs(rel) {
|
|
4295
|
+
rel = String(rel || '');
|
|
4296
|
+
if (/^[A-Za-z]:[\\/]/.test(rel) || rel.startsWith('/')) return rel;
|
|
4297
|
+
const cwd = String(currentSession?.cwd || '');
|
|
4298
|
+
if (!cwd) return rel;
|
|
4299
|
+
const sep = cwd.includes('\\') ? '\\' : '/';
|
|
4300
|
+
return cwd.replace(/[\\/]+$/, '') + sep + rel.split('/').join(sep);
|
|
4301
|
+
}
|
|
4302
|
+
window.feditCopyPath = function(btn) {
|
|
4303
|
+
const t = document.getElementById('fedit-path').textContent;
|
|
4304
|
+
const done = () => { const o = btn.textContent; btn.textContent = '✓ 已复制'; setTimeout(() => { btn.textContent = o; }, 1200); };
|
|
4305
|
+
(navigator.clipboard?.writeText(t) || Promise.reject()).then(done, () => { const x = document.createElement('textarea'); x.value = t; document.body.appendChild(x); x.select(); try { document.execCommand('copy'); done(); } catch {} x.remove(); });
|
|
4306
|
+
};
|
|
4307
|
+
async function feditFindByName(name) {
|
|
4308
|
+
try {
|
|
4309
|
+
const d = await (await fetch(`/api/files/${SESSION_ID}/search?q=${encodeURIComponent(name)}`)).json();
|
|
4310
|
+
const hits = (d.files || []).filter(f => !f.dir && f.name.split('/').pop() === name);
|
|
4311
|
+
return hits.length === 1 ? hits[0].name : null;
|
|
4312
|
+
} catch { return null; }
|
|
4313
|
+
}
|
|
4314
|
+
// HTML 预览令牌(见 server /view/:token):同一任务复用,过期前换新
|
|
4315
|
+
let _viewTok = null;
|
|
4316
|
+
async function feditViewBase() {
|
|
4317
|
+
if (!_viewTok || _viewTok.exp < Date.now()) {
|
|
4318
|
+
const d = await (await fetch(`/api/files/${SESSION_ID}/view-token`, { method: 'POST' })).json();
|
|
4319
|
+
if (!d.ok) throw new Error(d.error || '预览不可用');
|
|
4320
|
+
_viewTok = { token: d.token, exp: Date.now() + 3600_000 };
|
|
4321
|
+
}
|
|
4322
|
+
return '/view/' + _viewTok.token + '/';
|
|
4323
|
+
}
|
|
4324
|
+
const feditEncPath = (p) => String(p).split('/').map(encodeURIComponent).join('/');
|
|
4325
|
+
window.feditOpenTab = async function() {
|
|
4326
|
+
if (!_fedit) return;
|
|
4327
|
+
try { window.open((await feditViewBase()) + feditEncPath(_fedit.path), '_blank'); } catch (e) { addStatusMessage('打开失败: ' + e.message); }
|
|
4328
|
+
};
|
|
4329
|
+
// HTML 渲染:沙箱 iframe(不同源,页面脚本碰不到 myhi);内容用编辑框里的(没保存的修改也能看),
|
|
4330
|
+
// 注入 <base> 让图片 / CSS 等相对路径资源走只读预览链接
|
|
4331
|
+
async function feditRenderHtml(pv, src) {
|
|
4332
|
+
pv.innerHTML = '';
|
|
4333
|
+
let base;
|
|
4334
|
+
try { base = (await feditViewBase()) + feditEncPath(_fedit.path.split('/').slice(0, -1).join('/')) + (_fedit.path.includes('/') ? '/' : ''); }
|
|
4335
|
+
catch (e) { pv.textContent = '预览不可用:' + e.message; return; }
|
|
4336
|
+
const f = document.createElement('iframe');
|
|
4337
|
+
f.setAttribute('sandbox', 'allow-scripts allow-popups allow-forms allow-modals');
|
|
4338
|
+
const tag = '<base href="' + location.origin + base + '">';
|
|
4339
|
+
f.srcdoc = /<head[^>]*>/i.test(src) ? src.replace(/<head[^>]*>/i, (m) => m + tag) : tag + src;
|
|
4340
|
+
pv.appendChild(f);
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4234
4343
|
window.feditSetMode = function(mode) {
|
|
4235
4344
|
if (!_fedit) return;
|
|
4236
|
-
if (mode === 'preview' && !_fedit.md) mode = 'edit';
|
|
4345
|
+
if (mode === 'preview' && !_fedit.md && !_fedit.html) mode = 'edit';
|
|
4237
4346
|
_fedit.mode = mode;
|
|
4238
4347
|
const ta = document.getElementById('fedit-ta');
|
|
4239
4348
|
const pv = document.getElementById('fedit-preview');
|
|
4240
4349
|
ta.style.display = mode === 'edit' ? 'block' : 'none';
|
|
4241
4350
|
pv.style.display = mode === 'preview' ? 'block' : 'none';
|
|
4242
|
-
|
|
4351
|
+
pv.classList.toggle('html', mode === 'preview' && !!_fedit.html);
|
|
4352
|
+
document.getElementById('fedit-icon').textContent = mode === 'preview' ? '📄' : '✏️';
|
|
4353
|
+
if (mode === 'preview') { if (_fedit.html) feditRenderHtml(pv, ta.value); else pv.innerHTML = renderMarkdown(ta.value); }
|
|
4243
4354
|
document.getElementById('fedit-tab-edit').classList.toggle('on', mode === 'edit');
|
|
4244
4355
|
document.getElementById('fedit-tab-preview').classList.toggle('on', mode === 'preview');
|
|
4245
4356
|
};
|
|
@@ -4575,6 +4686,14 @@
|
|
|
4575
4686
|
if (b.dataset.v !== 'hide') settings.thinkCollapsed = b.dataset.v === 'fold';
|
|
4576
4687
|
saveSettings(); syncDisplaySegs();
|
|
4577
4688
|
}));
|
|
4689
|
+
const syncMobileSeg = () => document.querySelectorAll('#seg-mobile .seg').forEach(b => b.classList.toggle('active', b.dataset.v === (settings.mobileCompact === false ? 'off' : 'on')));
|
|
4690
|
+
syncMobileSeg();
|
|
4691
|
+
document.querySelectorAll('#seg-mobile .seg').forEach(b => b.addEventListener('click', () => {
|
|
4692
|
+
const v = b.dataset.v !== 'off';
|
|
4693
|
+
if ((settings.mobileCompact !== false) === v) return;
|
|
4694
|
+
settings.mobileCompact = v; saveSettings(); syncMobileSeg();
|
|
4695
|
+
location.reload(); // 布局类在页面头部就定了,切换后重载最干净
|
|
4696
|
+
}));
|
|
4578
4697
|
document.querySelectorAll('#seg-tools .seg').forEach(b => b.addEventListener('click', () => {
|
|
4579
4698
|
settings.collapseTools = b.dataset.v === 'fold'; saveSettings(); syncDisplaySegs();
|
|
4580
4699
|
}));
|
|
@@ -4603,6 +4722,104 @@
|
|
|
4603
4722
|
window.goHome = goHome;
|
|
4604
4723
|
window.goBack = function() { goHome(); };
|
|
4605
4724
|
|
|
4725
|
+
// ── 手机精简布局:⋯ 更多菜单 / 技能按钮 / 未读标记 / 其他任务提醒 ──────────
|
|
4726
|
+
const IS_M = document.documentElement.classList.contains('m');
|
|
4727
|
+
// 技能按钮:手机上快捷栏不平铺技能,点「技能」直接出可运行列表(底部有「管理技能」)
|
|
4728
|
+
window.skillBtnTap = function() { if (IS_M) openCmdSheet(); else openSkillSheet(); };
|
|
4729
|
+
|
|
4730
|
+
// ⋯ 菜单:状态行(在线/控制、项目说明、升级提示)和顶栏低频按钮都收在这;有待处理提示时 ⋯ 带红点
|
|
4731
|
+
const _shown = (id) => { const e = document.getElementById(id); return e && e.style.display !== 'none' && e.textContent.trim() ? e : null; };
|
|
4732
|
+
function mMoreDot() {
|
|
4733
|
+
const g = _shown('guide-chip');
|
|
4734
|
+
document.getElementById('m-more')?.classList.toggle('dot', !!(_shown('update-badge') || _shown('claude-update-badge') || (g && g.textContent.includes('偏长'))));
|
|
4735
|
+
}
|
|
4736
|
+
if (IS_M) new MutationObserver(mMoreDot).observe(document.getElementById('status-bar'), { subtree: true, childList: true, attributes: true, characterData: true });
|
|
4737
|
+
window.openMobileMore = function() {
|
|
4738
|
+
const items = [];
|
|
4739
|
+
const add = (icon, text, fn, color) => items.push({ icon, text, fn, color });
|
|
4740
|
+
add('📁', '文件', () => openFilePanel());
|
|
4741
|
+
const ctx = _shown('ctx-chip'); if (ctx) add('◈', '会话数据(上下文 ' + ctx.textContent.replace(/[^\d%]/g, '') + ')', () => openCtxSheet());
|
|
4742
|
+
const vc = _shown('viewer-count'), cb = _shown('control-badge');
|
|
4743
|
+
if (vc || cb) add('👥', [vc?.textContent, cb?.textContent].filter(Boolean).join(' · '), () => cb && toggleControl());
|
|
4744
|
+
const g = _shown('guide-chip'); if (g) add('', g.textContent, () => showMemory('project'), g.textContent.includes('偏长') ? 'var(--yellow)' : '');
|
|
4745
|
+
const u = _shown('update-badge'); if (u) add('', 'myhi 有更新:' + u.textContent.replace('⬆', '').trim(), () => doUpdate(), 'var(--yellow)');
|
|
4746
|
+
const cu = _shown('claude-update-badge'); if (cu) add('', 'Claude 有更新:' + cu.textContent.replace('⬆', '').trim(), () => doClaudeUpdate(), 'var(--blue)');
|
|
4747
|
+
add('⚙', '设置', () => openSettings());
|
|
4748
|
+
add('❓', '使用说明', () => openChatHelp());
|
|
4749
|
+
const ov = document.createElement('div');
|
|
4750
|
+
ov.style.cssText = 'position:fixed;inset:0;z-index:120;background:rgba(0,0,0,0.5);display:flex;align-items:flex-end';
|
|
4751
|
+
const esc2 = (t) => { const d = document.createElement('div'); d.textContent = t; return d.innerHTML; };
|
|
4752
|
+
ov.innerHTML = '<div style="background:var(--surface);border-radius:18px 18px 0 0;width:100%;padding:0.4rem 0 max(0.8rem,env(safe-area-inset-bottom))">' +
|
|
4753
|
+
'<div style="padding:0.5rem 1.1rem 0.3rem;font-size:0.72rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc2(document.getElementById('session-cwd')?.textContent || '') + '</div>' +
|
|
4754
|
+
items.map((it, i) => '<div data-i="' + i + '" style="padding:0.8rem 1.1rem;border-top:1px solid var(--surface2);font-size:0.9rem;cursor:pointer;color:' + (it.color || 'var(--text)') + '">' + (it.icon ? it.icon + ' ' : '') + esc2(it.text) + '</div>').join('') +
|
|
4755
|
+
'</div>';
|
|
4756
|
+
ov.onclick = (e) => { const r = e.target.closest('[data-i]'); ov.remove(); if (r) items[+r.dataset.i].fn(); };
|
|
4757
|
+
document.body.appendChild(ov);
|
|
4758
|
+
};
|
|
4759
|
+
|
|
4760
|
+
// 手机:手指往上推(往下看内容)收起顶栏,往下拉再出现;只跟手势走,AI 输出时的自动滚底不触发
|
|
4761
|
+
if (IS_M) {
|
|
4762
|
+
const bar = document.getElementById('top-bar');
|
|
4763
|
+
let y0 = null, hidden = false;
|
|
4764
|
+
const setHidden = (h) => {
|
|
4765
|
+
if (h === hidden) return; hidden = h;
|
|
4766
|
+
bar.style.marginTop = h ? -bar.offsetHeight + 'px' : '';
|
|
4767
|
+
};
|
|
4768
|
+
chatArea.addEventListener('touchstart', (e) => { y0 = e.touches[0].clientY; }, { passive: true });
|
|
4769
|
+
chatArea.addEventListener('touchmove', (e) => {
|
|
4770
|
+
if (y0 == null) return;
|
|
4771
|
+
const dy = e.touches[0].clientY - y0;
|
|
4772
|
+
if (Math.abs(dy) < 12) return;
|
|
4773
|
+
setHidden(dy < 0 && chatArea.scrollTop > 40);
|
|
4774
|
+
y0 = e.touches[0].clientY;
|
|
4775
|
+
}, { passive: true });
|
|
4776
|
+
chatArea.addEventListener('touchend', () => { y0 = null; }, { passive: true });
|
|
4777
|
+
chatArea.addEventListener('scroll', () => { if (chatArea.scrollTop < 10) setHidden(false); }, { passive: true });
|
|
4778
|
+
}
|
|
4779
|
+
|
|
4780
|
+
// 本页在看 = 本任务已读(切换面板 / 首页据此算「新完成」)
|
|
4781
|
+
let _seenAt = 0;
|
|
4782
|
+
function markSeenNow(force) {
|
|
4783
|
+
if (document.hidden || !window.myhiAttn) return;
|
|
4784
|
+
if (!force && Date.now() - _seenAt < 2000) return;
|
|
4785
|
+
_seenAt = Date.now(); myhiAttn.markSeen(SESSION_ID);
|
|
4786
|
+
}
|
|
4787
|
+
markSeenNow(true);
|
|
4788
|
+
document.addEventListener('visibilitychange', () => markSeenNow(true));
|
|
4789
|
+
window.addEventListener('pagehide', () => markSeenNow(true));
|
|
4790
|
+
socket.on('agent:message', () => markSeenNow());
|
|
4791
|
+
|
|
4792
|
+
// 其他任务的提醒:手机上每 8 秒拉一次列表(页面可见时),有任务转为「等你回复」或刚跑完就弹提示条,点了直接切过去
|
|
4793
|
+
let _attnSnap = null, _toastTimer = null;
|
|
4794
|
+
function mToast(s, kind) {
|
|
4795
|
+
const el = document.getElementById('m-toast'); if (!el) return;
|
|
4796
|
+
const esc2 = (t) => { const d = document.createElement('div'); d.textContent = t || ''; return d.innerHTML; };
|
|
4797
|
+
el.style.borderLeftColor = myhiAttn.color[kind] || 'var(--green)';
|
|
4798
|
+
el.innerHTML = '<div>「' + esc2(s.title || '(无标题)') + '」' + (kind === 'wait' ? '在等你回复' : '已完成') + ' <span style="color:var(--muted);font-size:0.72rem">点此切换</span></div>' +
|
|
4799
|
+
(s.lastText ? '<div class="sub">' + esc2(s.lastText) + '</div>' : '');
|
|
4800
|
+
el.onclick = () => { window.location.href = '/terminal/' + s.id; };
|
|
4801
|
+
el.classList.add('show');
|
|
4802
|
+
clearTimeout(_toastTimer); _toastTimer = setTimeout(() => el.classList.remove('show'), 8000);
|
|
4803
|
+
}
|
|
4804
|
+
function attnCheck(list) {
|
|
4805
|
+
if (!IS_M || !window.myhiAttn || !Array.isArray(list)) return;
|
|
4806
|
+
myhiAttn.init(list);
|
|
4807
|
+
const me = list.find(x => x.id === SESSION_ID)?.owner;
|
|
4808
|
+
const snap = {};
|
|
4809
|
+
for (const s of list) {
|
|
4810
|
+
const st = s.pending > 0 ? 'wait' : s.busy ? 'busy' : '';
|
|
4811
|
+
snap[s.id] = st;
|
|
4812
|
+
// 只提醒自己的任务(管理员的列表里有别人的任务,别人的完成不该弹给你)
|
|
4813
|
+
if (!_attnSnap || s.id === SESSION_ID || !(s.id in _attnSnap) || (me && s.owner && s.owner !== me)) continue;
|
|
4814
|
+
const was = _attnSnap[s.id];
|
|
4815
|
+
if (st === 'wait' && was !== 'wait') mToast(s, 'wait');
|
|
4816
|
+
else if (was === 'busy' && st === '') mToast(s, 'done');
|
|
4817
|
+
}
|
|
4818
|
+
_attnSnap = snap;
|
|
4819
|
+
}
|
|
4820
|
+
socket.on('sessions', attnCheck);
|
|
4821
|
+
if (IS_M) setInterval(() => { if (!document.hidden && socket.connected) socket.emit('list'); }, 8000);
|
|
4822
|
+
|
|
4606
4823
|
// ── 快速切换会话(免退出到首页)──────────────────────────
|
|
4607
4824
|
function switchRelTime(ms) {
|
|
4608
4825
|
if (!ms) return '';
|
|
@@ -4624,6 +4841,8 @@
|
|
|
4624
4841
|
sessions = await res.json();
|
|
4625
4842
|
} catch { addStatusMessage && addStatusMessage('会话列表加载失败'); return; }
|
|
4626
4843
|
sessions.sort((a, b) => switchSessTime(b) - switchSessTime(a)); // 最新在前
|
|
4844
|
+
const A = window.myhiAttn; if (A) A.init(sessions);
|
|
4845
|
+
const attnOf = (s) => (A && s.id !== SESSION_ID ? A.of(s) : (s.pending > 0 ? 'wait' : s.busy ? 'busy' : ''));
|
|
4627
4846
|
const esc2 = (s) => { const d = document.createElement('div'); d.textContent = s == null ? '' : s; return d.innerHTML; };
|
|
4628
4847
|
let mode = localStorage.getItem('myhi_group_mode') || 'time'; // 与首页共用记忆
|
|
4629
4848
|
|
|
@@ -4631,12 +4850,15 @@
|
|
|
4631
4850
|
const cur = s.id === SESSION_ID;
|
|
4632
4851
|
const proj = (s.cwd || '').replace(/\\/g, '/').split('/').filter(Boolean).slice(-1)[0] || '';
|
|
4633
4852
|
const tags = (s.tags || []).map(x => '<span style="font-size:0.62rem;color:var(--text3);background:rgba(124,58,237,0.14);border:1px solid rgba(124,58,237,0.35);border-radius:999px;padding:0 0.4rem">' + esc2(x) + '</span>').join(' ');
|
|
4634
|
-
const
|
|
4853
|
+
const at = attnOf(s);
|
|
4854
|
+
const sub = [A && at ? A.label[at] : (s.busy ? '运行中' : ''), proj, switchRelTime(switchSessTime(s)), s.controlHolderName ? (s.controlHolderName + ' 控制中') : ''].filter(Boolean).join(' · ');
|
|
4855
|
+
const dotC = at && A ? A.color[at] : (s.alive ? 'var(--green)' : 'var(--dim)');
|
|
4635
4856
|
return '<div data-sid="' + esc2(s.id) + '" style="display:flex;align-items:center;gap:0.6rem;padding:0.7rem 1.1rem;border-top:1px solid var(--surface2);cursor:pointer;' + (cur ? 'background:rgba(124,58,237,0.12)' : '') + '">' +
|
|
4636
|
-
'<span style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:' + (
|
|
4857
|
+
'<span style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:' + dotC + (at === 'wait' || at === 'busy' ? ';animation:pulse 1s infinite' : '') + '"></span>' +
|
|
4637
4858
|
'<div style="flex:1;min-width:0">' +
|
|
4638
4859
|
'<div style="font-size:0.9rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc2(s.title || '(无标题)') + ' ' + (cur ? '<span style="font-size:0.68rem;color:var(--purple)">· 当前</span>' : '') + '</div>' +
|
|
4639
4860
|
'<div style="font-size:0.72rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc2(sub) + '</div>' +
|
|
4861
|
+
(s.lastText ? '<div style="font-size:0.72rem;color:var(--text2, var(--muted));opacity:0.85;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">🤖 ' + esc2(s.lastText) + '</div>' : '') +
|
|
4640
4862
|
(tags ? '<div style="display:flex;flex-wrap:wrap;gap:0.25rem;margin-top:0.25rem">' + tags + '</div>' : '') +
|
|
4641
4863
|
'</div></div>';
|
|
4642
4864
|
};
|
|
@@ -4659,7 +4881,12 @@
|
|
|
4659
4881
|
if (untag.length) h += groupHdr('未分类', untag.length) + untag.map(rowHTML).join('');
|
|
4660
4882
|
return h;
|
|
4661
4883
|
}
|
|
4662
|
-
|
|
4884
|
+
// 最近:需要你关注的排前面(等你回复 > 执行中 > 新完成),其余按时间
|
|
4885
|
+
const buckets = { wait: [], busy: [], done: [], '': [] };
|
|
4886
|
+
for (const s of sessions) buckets[attnOf(s)].push(s);
|
|
4887
|
+
if (!buckets.wait.length && !buckets.busy.length && !buckets.done.length) return sessions.map(rowHTML).join('');
|
|
4888
|
+
return ['wait', 'busy', 'done', ''].filter(k => buckets[k].length)
|
|
4889
|
+
.map(k => groupHdr(k ? ({ wait: '🟠 等你回复', busy: '🔵 执行中', done: '🟢 新完成' })[k] : '其他', buckets[k].length) + buckets[k].map(rowHTML).join('')).join('');
|
|
4663
4890
|
};
|
|
4664
4891
|
|
|
4665
4892
|
const overlay = document.createElement('div');
|
|
@@ -6147,19 +6374,23 @@
|
|
|
6147
6374
|
filterInp.value = '';
|
|
6148
6375
|
const render = (keyword = '') => {
|
|
6149
6376
|
const kw = keyword.toLowerCase();
|
|
6150
|
-
//
|
|
6377
|
+
// 命令面板只列用户/项目技能(内置技能在快捷栏直接显示);手机精简布局快捷栏不平铺技能 → 内置也列进来
|
|
6378
|
+
const mob = document.documentElement.classList.contains('m');
|
|
6379
|
+
document.getElementById('cmd-sheet-title').textContent = mob ? '技能' : '自定义命令';
|
|
6151
6380
|
const filtered = _customSkills.filter(s =>
|
|
6152
|
-
s.source !== 'builtin' && (!kw || s.name.toLowerCase().includes(kw) || (s.desc || '').toLowerCase().includes(kw)));
|
|
6153
|
-
|
|
6381
|
+
(mob || s.source !== 'builtin') && (!kw || s.name.toLowerCase().includes(kw) || (s.desc || '').toLowerCase().includes(kw)));
|
|
6382
|
+
filtered.sort((a, b) => (a.source === 'builtin') - (b.source === 'builtin'));
|
|
6383
|
+
listEl.innerHTML = (filtered.length
|
|
6154
6384
|
? filtered.map(s => `<div class="action-sheet-item" onclick="runSkillAndClose('${escHtml(s.name)}', '${s.kind || 'command'}')">
|
|
6155
|
-
<div><div style="color:var(--purple3)">${s.kind === 'skill' ? '🧠 ' : '/'}${escHtml(s.name)}</div>${s.desc ? `<div class="desc">${escHtml(s.desc)}</div>` : ''}</div>
|
|
6385
|
+
<div><div style="color:${s.source === 'builtin' ? 'var(--teal)' : 'var(--purple3)'}">${s.kind === 'skill' ? '🧠 ' : '/'}${escHtml(s.name)}</div>${s.desc ? `<div class="desc">${escHtml(s.desc)}</div>` : ''}</div>
|
|
6156
6386
|
</div>`).join('')
|
|
6157
|
-
: '<div style="text-align:center;color:var(--muted);padding:1.5rem 0;font-size:0.82rem">无匹配命令</div>'
|
|
6387
|
+
: '<div style="text-align:center;color:var(--muted);padding:1.5rem 0;font-size:0.82rem">无匹配命令</div>')
|
|
6388
|
+
+ (mob ? `<div class="action-sheet-item" onclick="closeCmdSheet();openSkillSheet()"><div><div style="color:var(--muted)">⚙ 管理技能(生成 / 编辑 / 分享 / 导入)</div></div></div>` : '');
|
|
6158
6389
|
};
|
|
6159
6390
|
render();
|
|
6160
6391
|
filterInp.oninput = (e) => render(e.target.value);
|
|
6161
6392
|
sheet.classList.add('open');
|
|
6162
|
-
setTimeout(() => filterInp.focus(), 100);
|
|
6393
|
+
if (!document.documentElement.classList.contains('m')) setTimeout(() => filterInp.focus(), 100); // 手机上自动聚焦会弹键盘挡住列表
|
|
6163
6394
|
};
|
|
6164
6395
|
window.closeCmdSheet = function() {
|
|
6165
6396
|
document.getElementById('cmd-sheet').classList.remove('open');
|