dsh-remote-plugin 0.6.0 → 0.6.1
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/apk/dsh-remote.apk +0 -0
- package/gateway.cjs +5 -0
- package/index.mjs +68 -3
- package/package.json +1 -1
- package/public/admin.html +17 -0
- package/public/admin.js +9 -0
- package/public/app.js +314 -11
- package/public/desktop/desktop.html +158 -15
- package/public/desktop/desktop.js +183 -0
- package/public/donate.png +0 -0
- package/public/index.html +267 -85
- package/public/update.json +4 -4
- package/public/version.json +1 -1
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
<div class="ds-top-right">
|
|
64
64
|
<span class="ds-conn" id="conn-badge" title="">●</span>
|
|
65
65
|
<span class="ds-server" id="server-badge"></span>
|
|
66
|
+
<button id="btn-donate" class="ds-icon-btn" data-i18n-aria="ds.donate" data-i18n-title="ds.donate">🎁</button>
|
|
66
67
|
<button id="btn-stats-top" class="ds-icon-btn" data-i18n-aria="ds.stats" data-i18n-title="ds.stats">📊</button>
|
|
67
68
|
</div>
|
|
68
69
|
</header>
|
|
@@ -79,6 +80,21 @@
|
|
|
79
80
|
<div id="history" class="ds-history" aria-live="polite"></div>
|
|
80
81
|
<div class="ds-composer">
|
|
81
82
|
<textarea id="composer" rows="1" data-i18n-placeholder="ds.composerPlaceholder" placeholder="输入消息…"></textarea>
|
|
83
|
+
<div style="position:relative">
|
|
84
|
+
<button id="btn-cmd" class="ds-btn" data-i18n="ds.commands">指令</button>
|
|
85
|
+
<div id="cmd-menu" class="ds-group-menu hidden" style="width:280px; left:auto; right:0; top:auto; bottom:calc(100% + 8px)">
|
|
86
|
+
<button class="ds-feedback-item" data-ds-cmd="/compact" data-i18n="ds.cmdCompact">/compact 压缩对话历史</button>
|
|
87
|
+
<button class="ds-feedback-item" data-ds-cmd="/export" data-i18n="ds.cmdExport">/export 导出会话日志 ZIP</button>
|
|
88
|
+
<button class="ds-feedback-item" data-ds-cmd="/feedback" data-i18n="ds.cmdFeedback">/feedback 反馈当前会话</button>
|
|
89
|
+
<button class="ds-feedback-item" data-ds-cmd="/goal" data-i18n="ds.cmdGoal">/goal 设置/查看任务目标</button>
|
|
90
|
+
<button class="ds-feedback-item" data-ds-cmd="/permission" data-i18n="ds.cmdPermission">/permission 切换权限预设</button>
|
|
91
|
+
<button class="ds-feedback-item" data-ds-cmd="/plan" data-i18n="ds.cmdPlan">/plan 进入/退出计划模式</button>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div style="position:relative">
|
|
95
|
+
<button id="btn-preset" class="ds-btn" data-i18n="ds.presets">预设</button>
|
|
96
|
+
<div id="preset-menu" class="ds-group-menu hidden" style="width:260px; left:auto; right:0; top:auto; bottom:calc(100% + 8px)"></div>
|
|
97
|
+
</div>
|
|
82
98
|
<button id="btn-send" class="ds-btn primary" data-i18n="ds.send">发送</button>
|
|
83
99
|
</div>
|
|
84
100
|
</section>
|
|
@@ -97,7 +113,64 @@
|
|
|
97
113
|
<!-- 设置 -->
|
|
98
114
|
<section id="view-settings" class="ds-view hidden">
|
|
99
115
|
<div class="ds-section-label" data-i18n="ds.settings">设置</div>
|
|
100
|
-
<div
|
|
116
|
+
<div id="settings-home">
|
|
117
|
+
<div class="ds-settings">
|
|
118
|
+
<div class="ds-setting-row" data-settings-group="general" style="cursor:pointer">
|
|
119
|
+
<div><div class="ds-setting-name" data-i18n="ds.groupGeneral">通用</div><div class="ds-setting-desc" data-i18n="ds.groupGeneralDesc">工具调用、预设提示词</div></div>
|
|
120
|
+
<span class="ds-feedback-item" style="font-size:18px">›</span>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="ds-setting-row" data-settings-group="servers" style="cursor:pointer">
|
|
123
|
+
<div><div class="ds-setting-name" data-i18n="ds.groupServers">服务器</div><div class="ds-setting-desc" data-i18n="ds.groupServersDesc">服务器地址</div></div>
|
|
124
|
+
<span class="ds-feedback-item" style="font-size:18px">›</span>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="ds-setting-row" data-settings-group="notify" style="cursor:pointer">
|
|
127
|
+
<div><div class="ds-setting-name" data-i18n="ds.groupNotify">通知</div><div class="ds-setting-desc" data-i18n="ds.groupNotifyDesc">通知与提醒</div></div>
|
|
128
|
+
<span class="ds-feedback-item" style="font-size:18px">›</span>
|
|
129
|
+
</div>
|
|
130
|
+
<div class="ds-setting-row" data-settings-group="theme" style="cursor:pointer">
|
|
131
|
+
<div><div class="ds-setting-name" data-i18n="ds.groupTheme">皮肤</div><div class="ds-setting-desc" data-i18n="ds.groupThemeDesc">配色主题</div></div>
|
|
132
|
+
<span class="ds-feedback-item" style="font-size:18px">›</span>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="ds-setting-row" data-settings-group="about" style="cursor:pointer">
|
|
135
|
+
<div><div class="ds-setting-name" data-i18n="ds.groupAbout">关于</div><div class="ds-setting-desc" data-i18n="ds.groupAboutDesc">版本信息</div></div>
|
|
136
|
+
<span class="ds-feedback-item" style="font-size:18px">›</span>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
<div class="ds-settings">
|
|
140
|
+
<div class="ds-setting-row">
|
|
141
|
+
<div><div class="ds-setting-name" data-i18n="ds.tokenTitle">访问令牌</div><div class="ds-setting-desc" id="token-desc"></div></div>
|
|
142
|
+
<button id="btn-copy-token" class="ds-btn" data-i18n="ds.copyToken">复制</button>
|
|
143
|
+
</div>
|
|
144
|
+
<div class="ds-setting-row">
|
|
145
|
+
<div><div class="ds-setting-name" data-i18n="ds.langTitle">语言 / Language</div></div>
|
|
146
|
+
<button id="btn-lang" class="ds-btn">EN</button>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="ds-setting-row">
|
|
149
|
+
<div><div class="ds-setting-name" data-i18n="ds.feedbackTitle">反馈渠道</div><div class="ds-setting-desc" data-i18n="ds.feedbackDesc">GitHub / Gitee / B站:反馈 bug、提建议、唠嗑</div></div>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="ds-feedback-links">
|
|
152
|
+
<a class="ds-btn" href="https://github.com/Blank-not-black/dsh-Remote" target="_blank" rel="noopener">GitHub</a>
|
|
153
|
+
<a class="ds-btn" href="https://gitee.com/Blankneverfails/dsh-Remote" target="_blank" rel="noopener">Gitee</a>
|
|
154
|
+
<a class="ds-btn" href="https://space.bilibili.com/419009275/dynamic" target="_blank" rel="noopener">B站</a>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div id="settings-page-general" class="ds-settings hidden">
|
|
160
|
+
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
161
|
+
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
162
|
+
<div class="ds-setting-name" data-i18n="ds.groupGeneral">通用</div>
|
|
163
|
+
</div>
|
|
164
|
+
<div class="ds-setting-row">
|
|
165
|
+
<div><div class="ds-setting-name" data-i18n="ds.emptyGroup">暂无设置项</div></div>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div id="settings-page-servers" class="ds-settings hidden">
|
|
170
|
+
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
171
|
+
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
172
|
+
<div class="ds-setting-name" data-i18n="ds.groupServers">服务器</div>
|
|
173
|
+
</div>
|
|
101
174
|
<div class="ds-setting-row">
|
|
102
175
|
<div><div class="ds-setting-name" data-i18n="ds.serversTitle">服务器(分组)</div><div class="ds-setting-desc" id="server-desc"></div></div>
|
|
103
176
|
<button id="btn-server-speed" class="ds-btn" data-i18n="ds.speedTest">测速</button>
|
|
@@ -115,25 +188,37 @@
|
|
|
115
188
|
<input id="server-input" type="url" placeholder="http://IP:8787">
|
|
116
189
|
<button id="btn-server-add" class="ds-btn" data-i18n="ds.addServer">添加</button>
|
|
117
190
|
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div id="settings-page-notify" class="ds-settings hidden">
|
|
194
|
+
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
195
|
+
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
196
|
+
<div class="ds-setting-name" data-i18n="ds.groupNotify">通知</div>
|
|
197
|
+
</div>
|
|
118
198
|
<div class="ds-setting-row">
|
|
119
|
-
<div><div class="ds-setting-name" data-i18n="ds.
|
|
120
|
-
|
|
199
|
+
<div><div class="ds-setting-name" data-i18n="ds.emptyGroup">暂无设置项</div></div>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<div id="settings-page-theme" class="ds-settings hidden">
|
|
204
|
+
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
205
|
+
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
206
|
+
<div class="ds-setting-name" data-i18n="ds.groupTheme">皮肤</div>
|
|
121
207
|
</div>
|
|
122
208
|
<div class="ds-setting-row">
|
|
123
209
|
<div><div class="ds-setting-name" data-i18n="ds.themeTitle">皮肤</div><div class="ds-setting-desc" data-i18n="ds.themeDesc">四套皮肤</div></div>
|
|
124
210
|
<button id="btn-theme" class="ds-btn">默认深空</button>
|
|
125
211
|
</div>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
<div
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<div id="settings-page-about" class="ds-settings hidden">
|
|
215
|
+
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
216
|
+
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
217
|
+
<div class="ds-setting-name" data-i18n="ds.groupAbout">关于</div>
|
|
132
218
|
</div>
|
|
133
|
-
<div class="ds-
|
|
134
|
-
<
|
|
135
|
-
<
|
|
136
|
-
<a class="ds-btn" href="https://space.bilibili.com/419009275/dynamic" target="_blank" rel="noopener">B站</a>
|
|
219
|
+
<div class="ds-setting-row" id="btn-donate-about" style="cursor:pointer">
|
|
220
|
+
<div><div class="ds-setting-name" data-i18n="ds.donate">赞赏支持</div><div class="ds-setting-desc" data-i18n="ds.donateDesc">如果 dsh-remote 帮到了你,欢迎赞赏支持开发 ☕</div></div>
|
|
221
|
+
<span class="ds-feedback-item" style="font-size:18px">›</span>
|
|
137
222
|
</div>
|
|
138
223
|
</div>
|
|
139
224
|
</section>
|
|
@@ -191,6 +276,38 @@
|
|
|
191
276
|
</div>
|
|
192
277
|
</div>
|
|
193
278
|
|
|
279
|
+
<!-- 赞赏支持模态 -->
|
|
280
|
+
<div id="modal-donate" class="ds-modal hidden">
|
|
281
|
+
<div class="ds-modal-card">
|
|
282
|
+
<div class="ds-modal-title" data-i18n="ds.donate">赞赏支持</div>
|
|
283
|
+
<div class="ds-modal-body donate-body">
|
|
284
|
+
<img src="../donate.png" alt="" class="donate-img" style="display:block;margin:0 auto;max-width:100%;max-height:60vh;border-radius:8px">
|
|
285
|
+
<p class="donate-thanks" data-i18n="ds.donateThanks" style="text-align:center;margin-top:12px">感谢你的支持 ☕</p>
|
|
286
|
+
</div>
|
|
287
|
+
<div class="ds-modal-actions">
|
|
288
|
+
<button id="btn-donate-close" class="ds-btn" data-i18n="ds.donateClose">关闭</button>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
<!-- 更新内容模态 -->
|
|
294
|
+
<div id="modal-notes" class="ds-modal hidden">
|
|
295
|
+
<div class="ds-modal-card">
|
|
296
|
+
<div class="ds-modal-title"><span id="notes-version" style="opacity:.75"></span> <span data-i18n="ds.notesTitle">更新内容</span></div>
|
|
297
|
+
<div class="ds-modal-body notes-body">
|
|
298
|
+
<div id="notes-pages" class="notes-pages" style="display:flex;overflow-x:auto;scroll-snap-type:x mandatory;gap:12px;scrollbar-width:none;-ms-overflow-style:none;"></div>
|
|
299
|
+
<div class="notes-nav" style="display:flex;align-items:center;justify-content:center;gap:12px;margin-top:8px;">
|
|
300
|
+
<button id="notes-prev" class="ds-btn" aria-label="‹">‹</button>
|
|
301
|
+
<span id="notes-page" style="opacity:.75">1/1</span>
|
|
302
|
+
<button id="notes-next" class="ds-btn" aria-label="›">›</button>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
<div class="ds-modal-actions">
|
|
306
|
+
<button id="notes-close" class="ds-btn" data-i18n="ds.notesClose">关闭</button>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
|
|
194
311
|
<div id="toast" class="ds-toast hidden"></div>
|
|
195
312
|
<div id="ds-tip" class="ds-tip hidden" role="tooltip" aria-hidden="true"></div>
|
|
196
313
|
|
|
@@ -199,8 +316,20 @@
|
|
|
199
316
|
zh: {
|
|
200
317
|
'ds.repo': 'GitHub 仓库', 'ds.newSession': '+ 新会话', 'ds.sessions': '会话',
|
|
201
318
|
'ds.files': '文件传输', 'ds.settings': '设置', 'ds.stats': '统计', 'ds.menu': '导航',
|
|
202
|
-
'ds.send': '发送', 'ds.composerPlaceholder': '输入消息,Enter 发送…',
|
|
319
|
+
'ds.send': '发送', 'ds.composerPlaceholder': '输入消息,Enter 发送…', 'ds.presets': '预设',
|
|
320
|
+
'ds.commands': '指令',
|
|
321
|
+
'ds.cmdCompact': '/compact 压缩对话历史', 'ds.cmdExport': '/export 导出会话日志 ZIP',
|
|
322
|
+
'ds.cmdFeedback': '/feedback 反馈当前会话', 'ds.cmdGoal': '/goal 设置/查看任务目标',
|
|
323
|
+
'ds.cmdPermission': '/permission 切换权限预设', 'ds.cmdPlan': '/plan 进入/退出计划模式',
|
|
203
324
|
'ds.fsUp': '上级', 'ds.fsRefresh': '刷新', 'ds.fsEmpty': '目录为空',
|
|
325
|
+
'ds.groupGeneral': '通用', 'ds.groupGeneralDesc': '工具调用、预设提示词',
|
|
326
|
+
'ds.groupServers': '服务器', 'ds.groupServersDesc': '服务器地址',
|
|
327
|
+
'ds.groupNotify': '通知', 'ds.groupNotifyDesc': '通知与提醒',
|
|
328
|
+
'ds.groupTheme': '皮肤', 'ds.groupThemeDesc': '配色主题',
|
|
329
|
+
'ds.groupAbout': '关于', 'ds.groupAboutDesc': '版本信息',
|
|
330
|
+
'ds.donate': '赞赏支持', 'ds.donateDesc': '如果 dsh-remote 帮到了你,欢迎赞赏支持开发 ☕', 'ds.donateThanks': '感谢你的支持 ☕', 'ds.donateClose': '关闭',
|
|
331
|
+
'ds.notesTitle': '更新内容', 'ds.notesClose': '关闭', 'ds.notesPage': '{current}/{total}',
|
|
332
|
+
'ds.back': '‹ 返回', 'ds.emptyGroup': '暂无设置项',
|
|
204
333
|
'ds.serversTitle': '服务器(分组)', 'ds.speedTest': '测速', 'ds.currentGroup': '当前组',
|
|
205
334
|
'ds.addGroup': '+ 组', 'ds.addServer': '添加', 'ds.tokenTitle': '访问令牌', 'ds.copyToken': '复制',
|
|
206
335
|
'ds.themeTitle': '皮肤', 'ds.themeDesc': '默认深空 / 落日 / 易北爱乐厅 / 草原孤塔', 'ds.langTitle': '语言 / Language',
|
|
@@ -255,6 +384,7 @@
|
|
|
255
384
|
'ds.groupsConfirmDelete': '删除组「{group}」?组内服务器将归入默认组。', 'ds.groupsDeleted': '组已删除',
|
|
256
385
|
'ds.theme.default': '默认深空', 'ds.theme.dark': '落日', 'ds.theme.light': '易北爱乐厅', 'ds.theme.neutral': '草原孤塔',
|
|
257
386
|
'ds.role.me': '我', 'ds.role.dsh': 'DSH', 'ds.toolDefault': '工具',
|
|
387
|
+
'ds.eventSystemReminder': '系统提示',
|
|
258
388
|
'ds.questionOptions': '选项', 'ds.questionCustom': '自定义回答',
|
|
259
389
|
'ds.questionNeedAnswer': '请选择一个选项或填写自定义回答', 'ds.questionSubmitted': '已提交回答',
|
|
260
390
|
'ds.questionFrom': '来自 {server}',
|
|
@@ -262,8 +392,20 @@
|
|
|
262
392
|
en: {
|
|
263
393
|
'ds.repo': 'GitHub repo', 'ds.newSession': '+ New session', 'ds.sessions': 'Sessions',
|
|
264
394
|
'ds.files': 'Files', 'ds.settings': 'Settings', 'ds.stats': 'Stats', 'ds.menu': 'Menu',
|
|
265
|
-
'ds.send': 'Send', 'ds.composerPlaceholder': 'Type a message, Enter to send…',
|
|
395
|
+
'ds.send': 'Send', 'ds.composerPlaceholder': 'Type a message, Enter to send…', 'ds.presets': 'Presets',
|
|
396
|
+
'ds.commands': 'Commands',
|
|
397
|
+
'ds.cmdCompact': '/compact Compress conversation history', 'ds.cmdExport': '/export Export session log ZIP',
|
|
398
|
+
'ds.cmdFeedback': '/feedback Feedback current session', 'ds.cmdGoal': '/goal Set/view task goal',
|
|
399
|
+
'ds.cmdPermission': '/permission Switch permission preset', 'ds.cmdPlan': '/plan Enter/exit plan mode',
|
|
266
400
|
'ds.fsUp': 'Up', 'ds.fsRefresh': 'Refresh', 'ds.fsEmpty': 'Empty directory',
|
|
401
|
+
'ds.groupGeneral': 'General', 'ds.groupGeneralDesc': 'Tool calls, prompt presets',
|
|
402
|
+
'ds.groupServers': 'Servers', 'ds.groupServersDesc': 'Server address',
|
|
403
|
+
'ds.groupNotify': 'Notifications', 'ds.groupNotifyDesc': 'Notifications & reminders',
|
|
404
|
+
'ds.groupTheme': 'Theme', 'ds.groupThemeDesc': 'Color themes',
|
|
405
|
+
'ds.groupAbout': 'About', 'ds.groupAboutDesc': 'Version info',
|
|
406
|
+
'ds.donate': 'Support', 'ds.donateDesc': 'If dsh-remote has been helpful to you, feel free to support development with a coffee ☕', 'ds.donateThanks': 'Thanks for your support ☕', 'ds.donateClose': 'Close',
|
|
407
|
+
'ds.notesTitle': 'What\'s New', 'ds.notesClose': 'Close', 'ds.notesPage': '{current}/{total}',
|
|
408
|
+
'ds.back': '‹ Back', 'ds.emptyGroup': 'No settings here',
|
|
267
409
|
'ds.serversTitle': 'Servers (groups)', 'ds.speedTest': 'Test', 'ds.currentGroup': 'Current group',
|
|
268
410
|
'ds.addGroup': '+ Group', 'ds.addServer': 'Add', 'ds.tokenTitle': 'Access token', 'ds.copyToken': 'Copy',
|
|
269
411
|
'ds.themeTitle': 'Theme', 'ds.themeDesc': 'Deep Space / Sunset / Elbphilharmonie / Prairie Tower', 'ds.langTitle': 'Language',
|
|
@@ -318,6 +460,7 @@
|
|
|
318
460
|
'ds.groupsConfirmDelete': 'Delete group "{group}"? Its servers move to the default group.', 'ds.groupsDeleted': 'Group deleted',
|
|
319
461
|
'ds.theme.default': 'Deep Space', 'ds.theme.dark': 'Sunset', 'ds.theme.light': 'Elbphilharmonie', 'ds.theme.neutral': 'Prairie Tower',
|
|
320
462
|
'ds.role.me': 'Me', 'ds.role.dsh': 'DSH', 'ds.toolDefault': 'tool',
|
|
463
|
+
'ds.eventSystemReminder': 'System reminder',
|
|
321
464
|
'ds.questionOptions': 'Options', 'ds.questionCustom': 'Custom answer',
|
|
322
465
|
'ds.questionNeedAnswer': 'Choose an option or write a custom answer', 'ds.questionSubmitted': 'Answer submitted',
|
|
323
466
|
'ds.questionFrom': 'From {server}',
|
|
@@ -96,6 +96,35 @@ function toast(text, kind = '') {
|
|
|
96
96
|
toast._t = setTimeout(() => el.classList.add('hidden'), 2600)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/* ---------------- 预设提示词 ---------------- */
|
|
100
|
+
const PRESETS_KEY = 'dshPromptPresets'
|
|
101
|
+
function readPresets() {
|
|
102
|
+
try {
|
|
103
|
+
const v = JSON.parse(LS.get(PRESETS_KEY, '[]') || '[]')
|
|
104
|
+
return Array.isArray(v) ? v.filter(p => p && typeof p.id === 'string' && typeof p.name === 'string' && typeof p.text === 'string') : []
|
|
105
|
+
} catch { return [] }
|
|
106
|
+
}
|
|
107
|
+
function renderPresetMenuDesktop() {
|
|
108
|
+
const btn = $('btn-preset')
|
|
109
|
+
const menu = $('preset-menu')
|
|
110
|
+
if (!btn || !menu) return
|
|
111
|
+
const list = readPresets()
|
|
112
|
+
btn.style.display = list.length ? '' : 'none'
|
|
113
|
+
menu.classList.add('hidden')
|
|
114
|
+
menu.innerHTML = list.map(p => `<button class="ds-feedback-item" data-ds-preset="${esc(p.id)}">${esc(p.name)}</button>`).join('')
|
|
115
|
+
}
|
|
116
|
+
function togglePresetMenuDesktop() {
|
|
117
|
+
const menu = $('preset-menu')
|
|
118
|
+
if (!menu) return
|
|
119
|
+
if (!readPresets().length) return
|
|
120
|
+
menu.classList.toggle('hidden')
|
|
121
|
+
}
|
|
122
|
+
function toggleCmdMenuDesktop() {
|
|
123
|
+
const menu = $('cmd-menu')
|
|
124
|
+
if (!menu) return
|
|
125
|
+
menu.classList.toggle('hidden')
|
|
126
|
+
}
|
|
127
|
+
|
|
99
128
|
/* ---------------- 反馈 ---------------- */
|
|
100
129
|
const FEEDBACK_LINKS = {
|
|
101
130
|
githubIssues: 'https://github.com/Blank-not-black/dsh-Remote/issues',
|
|
@@ -134,6 +163,64 @@ function openFeedbackModal() {
|
|
|
134
163
|
setTimeout(() => $('fb-msg').focus(), 50)
|
|
135
164
|
}
|
|
136
165
|
function closeFeedbackModal() { $('modal-feedback').classList.add('hidden') }
|
|
166
|
+
function openDonateModal() {
|
|
167
|
+
const m = $('modal-donate')
|
|
168
|
+
if (m) m.classList.remove('hidden')
|
|
169
|
+
}
|
|
170
|
+
/* ---------------- 更新内容弹窗 ---------------- */
|
|
171
|
+
const NOTES_KEY = 'seenNotesVersion'
|
|
172
|
+
let notesVersion = ''
|
|
173
|
+
let notesPages = []
|
|
174
|
+
let notesPage = 0
|
|
175
|
+
function splitNotes(notes) {
|
|
176
|
+
return String(notes || '').split(/[;;]/).map(s => s.trim()).filter(Boolean)
|
|
177
|
+
}
|
|
178
|
+
function renderNotesPages(items) {
|
|
179
|
+
const box = $('notes-pages')
|
|
180
|
+
if (!box) return
|
|
181
|
+
const pages = []
|
|
182
|
+
for (let i = 0; i < items.length; i += 3) pages.push(items.slice(i, i + 3))
|
|
183
|
+
notesPages = pages
|
|
184
|
+
notesPage = 0
|
|
185
|
+
box.innerHTML = pages.map(page => `<div class="notes-page" style="flex:0 0 100%;scroll-snap-align:start;box-sizing:border-box;min-width:0;">${page.map(item => `<div class="notes-item" style="padding:6px 0;line-height:1.5;">${esc(item)}</div>`).join('')}</div>`).join('')
|
|
186
|
+
box.scrollLeft = 0
|
|
187
|
+
updateNotesPage()
|
|
188
|
+
}
|
|
189
|
+
function updateNotesPage() {
|
|
190
|
+
const box = $('notes-pages')
|
|
191
|
+
const pageEl = $('notes-page')
|
|
192
|
+
if (!box || !pageEl) return
|
|
193
|
+
const total = notesPages.length || 1
|
|
194
|
+
const idx = Math.min(Math.max(0, Math.round(box.scrollLeft / Math.max(1, box.clientWidth))), total - 1)
|
|
195
|
+
notesPage = idx
|
|
196
|
+
pageEl.textContent = t('ds.notesPage', { current: idx + 1, total })
|
|
197
|
+
}
|
|
198
|
+
function scrollNotes(dir) {
|
|
199
|
+
const box = $('notes-pages')
|
|
200
|
+
if (box) box.scrollBy({ left: dir * box.clientWidth, behavior: 'smooth' })
|
|
201
|
+
}
|
|
202
|
+
function openNotesModal(info) {
|
|
203
|
+
if (!info?.version || String(info.version).includes('-rc')) return
|
|
204
|
+
if (LS.get(NOTES_KEY) === info.version) return
|
|
205
|
+
const items = splitNotes(info.notes)
|
|
206
|
+
if (!items.length) return
|
|
207
|
+
notesVersion = info.version
|
|
208
|
+
const vEl = $('notes-version')
|
|
209
|
+
if (vEl) vEl.textContent = 'v' + info.version
|
|
210
|
+
renderNotesPages(items)
|
|
211
|
+
$('modal-notes').classList.remove('hidden')
|
|
212
|
+
}
|
|
213
|
+
function closeNotesModal() {
|
|
214
|
+
$('modal-notes').classList.add('hidden')
|
|
215
|
+
if (notesVersion) { LS.set(NOTES_KEY, notesVersion); notesVersion = '' }
|
|
216
|
+
}
|
|
217
|
+
async function checkNotesOnStart() {
|
|
218
|
+
try {
|
|
219
|
+
const res = await fetch('../update.json?t=' + Date.now())
|
|
220
|
+
if (!res.ok) return
|
|
221
|
+
openNotesModal(await res.json())
|
|
222
|
+
} catch {}
|
|
223
|
+
}
|
|
137
224
|
async function submitFeedback() {
|
|
138
225
|
const type = document.querySelector('#fb-chips .ds-fb-chip.current')?.dataset.fbType || 'bug'
|
|
139
226
|
const message = $('fb-msg').value.trim()
|
|
@@ -735,6 +822,13 @@ function blockHtml(b) {
|
|
|
735
822
|
if (b.type === 'image') return `<div>🖼</div>`
|
|
736
823
|
return ''
|
|
737
824
|
}
|
|
825
|
+
function systemReminderText(blocks) {
|
|
826
|
+
if (!Array.isArray(blocks)) return ''
|
|
827
|
+
return blocks
|
|
828
|
+
.filter(b => b && typeof b === 'object' && b.type === 'text' && String(b.text ?? '').trimStart().startsWith('<system-reminder>'))
|
|
829
|
+
.map(b => String(b.text ?? ''))
|
|
830
|
+
.join('\n')
|
|
831
|
+
}
|
|
738
832
|
function eventHtml(entry) {
|
|
739
833
|
const ev = entry.event || {}
|
|
740
834
|
const data = ev.data || {}
|
|
@@ -744,6 +838,11 @@ function eventHtml(entry) {
|
|
|
744
838
|
const msg = data.message || {}
|
|
745
839
|
const role = data.role || msg.role || (type.startsWith('user') ? 'user' : 'assistant')
|
|
746
840
|
const blocks = msg.content || data.content || []
|
|
841
|
+
const sysText = type === 'user/message' ? systemReminderText(blocks) : ''
|
|
842
|
+
if (sysText) {
|
|
843
|
+
const shown = sysText.length > 400 ? sysText.slice(0, 400) + '…' : sysText
|
|
844
|
+
return `<details class="event ds-tool"><summary>${esc(t('ds.eventSystemReminder'))}</summary><pre>${esc(shown)}</pre></details>`
|
|
845
|
+
}
|
|
747
846
|
const text = blocks.map(blockHtml).join('')
|
|
748
847
|
return `<div class="ds-msg ${esc(role)}"><div class="role">${esc(role === 'user' ? t('ds.role.me') : t('ds.role.dsh'))}</div>${text || '<span style="opacity:.6">…</span>'}</div>`
|
|
749
848
|
}
|
|
@@ -767,10 +866,35 @@ function renderHistory() {
|
|
|
767
866
|
box.innerHTML = items.map(eventHtml).join('') || `<div class="ds-empty">${t('ds.historyEmpty')}</div>`
|
|
768
867
|
box.scrollTop = box.scrollHeight
|
|
769
868
|
}
|
|
869
|
+
async function runSlashCommand(text) {
|
|
870
|
+
const clean = String(text || '').trim()
|
|
871
|
+
if (!clean.startsWith('/') || !state.current) return false
|
|
872
|
+
try {
|
|
873
|
+
const signal = typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'
|
|
874
|
+
? AbortSignal.timeout(20000)
|
|
875
|
+
: undefined
|
|
876
|
+
const res = await fetch(apiUrl('/remote/api/command'), {
|
|
877
|
+
method: 'POST',
|
|
878
|
+
headers: { 'content-type': 'application/json', authorization: 'Bearer ' + state.token, 'x-dsh-remote-client': 'web' },
|
|
879
|
+
body: JSON.stringify({ sessionId: state.current, line: clean }),
|
|
880
|
+
...(signal ? { signal } : {})
|
|
881
|
+
})
|
|
882
|
+
if (res.status === 401) { toast(t('ds.toastAuth'), 'err'); return true }
|
|
883
|
+
if (!res.ok) return false
|
|
884
|
+
const data = await res.json().catch(() => null)
|
|
885
|
+
if (data?.ok === false) return true
|
|
886
|
+
return data?.ok === true && data.executed === true
|
|
887
|
+
} catch (e) {
|
|
888
|
+
console.error('slash command bridge failed', e)
|
|
889
|
+
}
|
|
890
|
+
return false
|
|
891
|
+
}
|
|
892
|
+
|
|
770
893
|
async function sendMessage() {
|
|
771
894
|
const input = $('composer')
|
|
772
895
|
const text = input.value.trim()
|
|
773
896
|
if (!text || !state.current) return
|
|
897
|
+
if (await runSlashCommand(text)) { input.value = ''; return }
|
|
774
898
|
input.value = ''
|
|
775
899
|
const v = await safeRpc('session.prompt', { sessionId: state.current, text }, '')
|
|
776
900
|
if (v) toast(t('ds.toastSent'), 'ok')
|
|
@@ -993,6 +1117,21 @@ function showView(id) {
|
|
|
993
1117
|
if (id === 'view-chat') { const s = state.byId.get(state.current); $('ds-title').textContent = s ? titleOf(s) : t('ds.sessions') }
|
|
994
1118
|
else $('ds-title').textContent = t(titles[id])
|
|
995
1119
|
if (id === 'view-files' && !state.fs.loaded) loadFs(null, true)
|
|
1120
|
+
if (id === 'view-settings') showSettingsHome()
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
const SETTINGS_GROUPS = ['general', 'servers', 'notify', 'theme', 'about']
|
|
1124
|
+
function showSettingsHome() {
|
|
1125
|
+
const home = $('settings-home')
|
|
1126
|
+
if (!home) return
|
|
1127
|
+
home.classList.remove('hidden')
|
|
1128
|
+
for (const name of SETTINGS_GROUPS) $('settings-page-' + name)?.classList.add('hidden')
|
|
1129
|
+
}
|
|
1130
|
+
function showSettingsPage(name) {
|
|
1131
|
+
const home = $('settings-home')
|
|
1132
|
+
if (!home || !SETTINGS_GROUPS.includes(name)) return
|
|
1133
|
+
home.classList.add('hidden')
|
|
1134
|
+
for (const g of SETTINGS_GROUPS) $('settings-page-' + g)?.classList.toggle('hidden', g !== name)
|
|
996
1135
|
}
|
|
997
1136
|
function updateConn() {
|
|
998
1137
|
const el = $('conn-badge')
|
|
@@ -1033,8 +1172,46 @@ function bindUi() {
|
|
|
1033
1172
|
$('composer').addEventListener('keydown', (e) => {
|
|
1034
1173
|
if (e.key === 'Enter' && !e.shiftKey && !e.isComposing) { e.preventDefault(); sendMessage() }
|
|
1035
1174
|
})
|
|
1175
|
+
renderPresetMenuDesktop()
|
|
1176
|
+
$('btn-cmd').addEventListener('click', (e) => { e.stopPropagation(); toggleCmdMenuDesktop() })
|
|
1177
|
+
$('cmd-menu').addEventListener('click', (e) => {
|
|
1178
|
+
const item = e.target.closest('[data-ds-cmd]')
|
|
1179
|
+
if (item) {
|
|
1180
|
+
const input = $('composer')
|
|
1181
|
+
input.value = item.dataset.dsCmd + ' '
|
|
1182
|
+
input.focus()
|
|
1183
|
+
$('cmd-menu').classList.add('hidden')
|
|
1184
|
+
}
|
|
1185
|
+
})
|
|
1186
|
+
$('btn-preset').addEventListener('click', (e) => { e.stopPropagation(); togglePresetMenuDesktop() })
|
|
1187
|
+
$('preset-menu').addEventListener('click', (e) => {
|
|
1188
|
+
const item = e.target.closest('[data-ds-preset]')
|
|
1189
|
+
if (item) {
|
|
1190
|
+
const found = readPresets().find(x => x.id === item.dataset.dsPreset)
|
|
1191
|
+
if (found) {
|
|
1192
|
+
const input = $('composer')
|
|
1193
|
+
input.value = found.text
|
|
1194
|
+
input.focus()
|
|
1195
|
+
}
|
|
1196
|
+
$('preset-menu').classList.add('hidden')
|
|
1197
|
+
}
|
|
1198
|
+
})
|
|
1199
|
+
document.addEventListener('click', (e) => {
|
|
1200
|
+
if (!e.target.closest('#preset-menu') && !e.target.closest('#btn-preset')) $('preset-menu')?.classList.add('hidden')
|
|
1201
|
+
if (!e.target.closest('#cmd-menu') && !e.target.closest('#btn-cmd')) $('cmd-menu')?.classList.add('hidden')
|
|
1202
|
+
})
|
|
1036
1203
|
$('btn-stats-top').addEventListener('click', toggleStatsDrawer)
|
|
1037
1204
|
$('stats-drawer-close').addEventListener('click', toggleStatsDrawer)
|
|
1205
|
+
// 赞赏支持
|
|
1206
|
+
$('btn-donate').addEventListener('click', openDonateModal)
|
|
1207
|
+
$('btn-donate-about').addEventListener('click', openDonateModal)
|
|
1208
|
+
$('btn-donate-close').addEventListener('click', () => $('modal-donate').classList.add('hidden'))
|
|
1209
|
+
// 更新内容弹窗
|
|
1210
|
+
$('notes-close').addEventListener('click', closeNotesModal)
|
|
1211
|
+
$('notes-prev').addEventListener('click', () => scrollNotes(-1))
|
|
1212
|
+
$('notes-next').addEventListener('click', () => scrollNotes(1))
|
|
1213
|
+
$('notes-pages').addEventListener('scroll', updateNotesPage)
|
|
1214
|
+
$('modal-notes').addEventListener('click', (e) => { if (e.target === $('modal-notes')) closeNotesModal() })
|
|
1038
1215
|
// 反馈
|
|
1039
1216
|
$('btn-feedback').addEventListener('click', (e) => { e.stopPropagation(); toggleFeedbackMenu() })
|
|
1040
1217
|
$('feedback-menu').addEventListener('click', (e) => {
|
|
@@ -1065,6 +1242,11 @@ function bindUi() {
|
|
|
1065
1242
|
})
|
|
1066
1243
|
$('stats-chart').addEventListener('mouseleave', hideTip)
|
|
1067
1244
|
|
|
1245
|
+
$('view-settings').addEventListener('click', (e) => {
|
|
1246
|
+
const group = e.target.closest('[data-settings-group]')
|
|
1247
|
+
if (group) { showSettingsPage(group.dataset.settingsGroup); return }
|
|
1248
|
+
if (e.target.closest('[data-settings-back]')) { showSettingsHome(); return }
|
|
1249
|
+
})
|
|
1068
1250
|
$('btn-server-speed').addEventListener('click', () => selectFastestServer({ silent: false }))
|
|
1069
1251
|
$('btn-server-add').addEventListener('click', addServer)
|
|
1070
1252
|
$('btn-group-add').addEventListener('click', addGroup)
|
|
@@ -1105,6 +1287,7 @@ async function start() {
|
|
|
1105
1287
|
$('token-desc').textContent = state.token ? '● ' + state.token.slice(0, 12) + '…' : t('ds.toastAuth')
|
|
1106
1288
|
bindUi()
|
|
1107
1289
|
updateConn()
|
|
1290
|
+
checkNotesOnStart()
|
|
1108
1291
|
if (state.token) {
|
|
1109
1292
|
if (state.servers.length) await selectFastestServer({ silent: true, reconnect: false })
|
|
1110
1293
|
openStreams()
|
|
Binary file
|