dsh-remote-plugin 0.6.18 → 0.6.19
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/package.json +1 -1
- package/public/admin.html +16 -17
- package/public/admin.js +6 -5
- package/public/app.js +52 -14
- package/public/desktop/desktop.css +48 -7
- package/public/desktop/desktop.html +23 -20
- package/public/desktop/desktop.js +72 -16
- package/public/index.html +31 -29
- package/public/motion.js +105 -17
- package/public/plugin.html +6 -5
- package/public/styles.css +56 -24
- package/public/theme-vars.css +244 -167
- package/public/theme.js +2 -2
- package/public/update.json +8 -8
- package/public/version.json +1 -1
package/apk/dsh-remote.apk
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-plugin",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.19",
|
|
4
4
|
"description": "DSH Remote 官方 bundle 插件:DSH 左侧原生边栏入口 + 右侧抽屉内嵌管理控制台;内置网关随 DSH 自动启停(systemd 独立单元),抽屉直显令牌与设备监控;网关提供 /fs/* 文件传输端点(列表/断点下载/上传),配合 Android App 远程操控会话/审批/提问/goal 与文件互传(多服务器测速切换、聊天记录离线缓存)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|
package/public/admin.html
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
-
<meta name="theme-color" content="#
|
|
6
|
+
<meta name="theme-color" content="#0D1117">
|
|
7
7
|
<title>DSH Remote · 管理</title>
|
|
8
|
-
<script>/* 首帧前应用皮肤 */ (function(){try{var t=localStorage.getItem('dshTheme');if(t!=='default'&&t!=='dark'&&t!=='light'&&t!=='neutral'){t=window.matchMedia('(prefers-color-scheme: light)').matches?'light':'default'}document.documentElement.setAttribute('data-theme',t)}catch(e){}})()</script>
|
|
8
|
+
<script>/* 首帧前应用皮肤 */ (function(){try{var t=localStorage.getItem('dshTheme');if(t!=='default'&&t!=='dark'&&t!=='light'&&t!=='neutral'&&t!=='mono'){t=window.matchMedia('(prefers-color-scheme: light)').matches?'light':'default'}document.documentElement.setAttribute('data-theme',t)}catch(e){}})()</script>
|
|
9
9
|
<link rel="stylesheet" href="../styles.css">
|
|
10
10
|
<style>
|
|
11
11
|
.admin-wrap { max-width: 1180px; margin: 0 auto; padding: calc(env(safe-area-inset-top, 0px) + 14px) 14px 40px; }
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
.device-key-toggle-actions { display:flex; align-items:center; gap:8px; flex:none; }
|
|
88
88
|
.device-key-switch { position:relative; width:42px; height:24px; flex:none; }
|
|
89
89
|
.device-key-switch input { position:absolute; opacity:0; pointer-events:none; }
|
|
90
|
-
.device-key-switch span { position:absolute; inset:0; border:1px solid var(--dsr-line); border-radius:999px; background:var(--dsr-bg-2); cursor:pointer; transition
|
|
91
|
-
.device-key-switch span::after { content:''; position:absolute; width:18px; height:18px; left:2px; top:2px; border-radius:50%; background:var(--dsr-muted); transition
|
|
90
|
+
.device-key-switch span { position:absolute; inset:0; border:1px solid var(--dsr-line); border-radius:999px; background:var(--dsr-bg-2); cursor:pointer; transition:background-color .18s ease,border-color .18s ease; }
|
|
91
|
+
.device-key-switch span::after { content:''; position:absolute; width:18px; height:18px; left:2px; top:2px; border-radius:50%; background:var(--dsr-muted); transition:transform .18s ease,background-color .18s ease; }
|
|
92
92
|
.device-key-switch input:checked + span { border-color:var(--dsr-accent-line); background:var(--dsr-accent-soft); }
|
|
93
93
|
.device-key-switch input:checked + span::after { transform:translateX(18px); background:var(--dsr-accent-strong); }
|
|
94
94
|
.device-key-switch input:focus-visible + span { outline:2px solid var(--dsr-accent-strong); outline-offset:2px; }
|
|
@@ -126,8 +126,8 @@
|
|
|
126
126
|
.host-ip-use { color: var(--dsr-muted); }
|
|
127
127
|
.host-ip-switch { position: relative; display: inline-block; width: 38px; height: 22px; vertical-align: middle; }
|
|
128
128
|
.host-ip-switch input { position: absolute; width: 1px; height: 1px; opacity: 0; }
|
|
129
|
-
.host-ip-switch span { position: absolute; inset: 0; border: 1px solid var(--dsr-line); border-radius: 999px; background: var(--dsr-bg-2); cursor: pointer; transition: .18s ease; }
|
|
130
|
-
.host-ip-switch span::after { content: ''; position: absolute; width: 16px; height: 16px; left: 2px; top: 2px; border-radius: 50%; background: var(--dsr-muted); transition: .18s ease; }
|
|
129
|
+
.host-ip-switch span { position: absolute; inset: 0; border: 1px solid var(--dsr-line); border-radius: 999px; background: var(--dsr-bg-2); cursor: pointer; transition: background-color .18s ease, border-color .18s ease; }
|
|
130
|
+
.host-ip-switch span::after { content: ''; position: absolute; width: 16px; height: 16px; left: 2px; top: 2px; border-radius: 50%; background: var(--dsr-muted); transition: transform .18s ease, background-color .18s ease; }
|
|
131
131
|
.host-ip-switch input:checked + span { border-color: var(--dsr-accent-line); background: var(--dsr-accent-soft); }
|
|
132
132
|
.host-ip-switch input:checked + span::after { transform: translateX(16px); background: var(--dsr-accent-strong); }
|
|
133
133
|
.host-ip-switch input:focus-visible + span { outline: 2px solid var(--dsr-accent-strong); outline-offset: 2px; }
|
|
@@ -186,7 +186,6 @@
|
|
|
186
186
|
width: 248px; background: var(--dsr-bg-2); border: 1px solid var(--dsr-line); border-radius: 14px;
|
|
187
187
|
box-shadow: 0 12px 34px var(--dsr-shadow); padding: 6px;
|
|
188
188
|
display: flex; flex-direction: column; gap: 2px;
|
|
189
|
-
animation: fb-in .18s ease;
|
|
190
189
|
}
|
|
191
190
|
.fb-item {
|
|
192
191
|
min-height: 44px; display: flex; align-items: center; gap: 10px;
|
|
@@ -204,7 +203,6 @@
|
|
|
204
203
|
.fb-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
|
|
205
204
|
.fb-name { font-weight: 600; }
|
|
206
205
|
.fb-desc { font-size: 11px; color: var(--dsr-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
207
|
-
@keyframes fb-in { from { opacity: 0; transform: translateY(-6px) } to { opacity: 1; transform: translateY(0) } }
|
|
208
206
|
/* 窄屏压缩顶栏: 图标化文字按钮, 保证全部按钮完整可见 */
|
|
209
207
|
@media (max-width: 900px) {
|
|
210
208
|
.gh-label, .t-label { display: none; }
|
|
@@ -331,8 +329,7 @@
|
|
|
331
329
|
@media (max-width: 900px) {
|
|
332
330
|
.admin-title { display: grid; grid-template-columns: minmax(0, 1fr) auto; row-gap: 10px; }
|
|
333
331
|
.admin-title .left { min-width: 0; }
|
|
334
|
-
.admin-title .right { grid-column: 1 / -1; justify-content: flex-start; min-width: 0;
|
|
335
|
-
.admin-title .right::-webkit-scrollbar { display: none; }
|
|
332
|
+
.admin-title .right { grid-column: 1 / -1; justify-content: flex-start; min-width: 0; flex-wrap: wrap; overflow: visible; }
|
|
336
333
|
}
|
|
337
334
|
@media (max-width: 440px) {
|
|
338
335
|
.admin-title h1 { display: block; min-width: 0; overflow: visible; font-size: 18px; }
|
|
@@ -381,12 +378,12 @@
|
|
|
381
378
|
</div>
|
|
382
379
|
</div>
|
|
383
380
|
|
|
384
|
-
<div id="login-view" class="login-card hidden">
|
|
385
|
-
<input id="token-input" type="password" placeholder="输入网关访问令牌" autocomplete="off" data-i18n-placeholder="tokenPlaceholder">
|
|
381
|
+
<div id="login-view" class="login-card hidden" data-motion-view>
|
|
382
|
+
<input id="token-input" name="gateway-token" type="password" placeholder="输入网关访问令牌" autocomplete="off" aria-label="网关访问令牌" data-i18n-placeholder="tokenPlaceholder" data-i18n-aria="tokenPlaceholder">
|
|
386
383
|
<button id="btn-login" class="mini-btn" data-i18n="enter">进入</button>
|
|
387
384
|
</div>
|
|
388
385
|
|
|
389
|
-
<div id="main-view" class="hidden">
|
|
386
|
+
<div id="main-view" class="hidden" data-motion-view>
|
|
390
387
|
<section id="admin-hero" class="admin-hero" aria-live="polite">
|
|
391
388
|
<div class="admin-hero-copy">
|
|
392
389
|
<div class="admin-eyebrow" data-i18n="hero.eyebrow">GATEWAY CONTROL</div>
|
|
@@ -455,8 +452,8 @@
|
|
|
455
452
|
</div>
|
|
456
453
|
|
|
457
454
|
<div id="gateway-port-row" class="gateway-port-row hidden">
|
|
458
|
-
<label data-i18n="gatewayPort">网关端口</label>
|
|
459
|
-
<input id="gateway-port-input" type="number" min="1" max="65535" inputmode="numeric" placeholder="8787">
|
|
455
|
+
<label for="gateway-port-input" data-i18n="gatewayPort">网关端口</label>
|
|
456
|
+
<input id="gateway-port-input" name="gateway-port" type="number" min="1" max="65535" inputmode="numeric" autocomplete="off" placeholder="8787">
|
|
460
457
|
<span id="gateway-port-current" class="muted">—</span>
|
|
461
458
|
<button id="btn-save-port" class="mini-btn" data-i18n="savePort">保存</button>
|
|
462
459
|
</div>
|
|
@@ -560,7 +557,7 @@
|
|
|
560
557
|
'doctor.realtime': '实时消息通道', 'doctor.realtimePass': 'mux 与 host 通道均已连接', 'doctor.realtimeFail': '实时通道未全部建立;可先使用轮询,检查 DSH 后会自动恢复',
|
|
561
558
|
'doctor.start': '启动', 'doctor.showQr': '显示二维码', 'doctor.copyAddress': '复制地址', 'doctor.copyCommand': '复制命令',
|
|
562
559
|
'doctor.reportCopied': '诊断报告已复制', 'doctor.commandCopied': '防火墙命令已复制,请确认网络范围后手动执行', 'doctor.addressCopied': '服务器地址已复制',
|
|
563
|
-
'theme.default': '默认深空', 'theme.dark': '落日', 'theme.light': '易北爱乐厅', 'theme.neutral': '草原孤塔',
|
|
560
|
+
'theme.default': '默认深空', 'theme.dark': '落日', 'theme.light': '易北爱乐厅', 'theme.neutral': '草原孤塔', 'theme.mono': '黑曜白',
|
|
564
561
|
'theme.panelTitle': '选择配色', 'theme.close': '关闭',
|
|
565
562
|
'repo': '仓库',
|
|
566
563
|
'donateTitle': '赞赏支持', 'donateThanks': '感谢你的支持 ☕',
|
|
@@ -670,7 +667,7 @@
|
|
|
670
667
|
'doctor.realtime': 'Realtime channels', 'doctor.realtimePass': 'Both mux and host channels are connected', 'doctor.realtimeFail': 'Realtime channels are incomplete. Polling remains available and recovery is automatic.',
|
|
671
668
|
'doctor.start': 'Start', 'doctor.showQr': 'Show QR', 'doctor.copyAddress': 'Copy address', 'doctor.copyCommand': 'Copy command',
|
|
672
669
|
'doctor.reportCopied': 'Diagnostic report copied', 'doctor.commandCopied': 'Firewall command copied. Review the network scope before running it.', 'doctor.addressCopied': 'Server address copied',
|
|
673
|
-
'theme.default': 'Default', 'theme.dark': 'Sunset', 'theme.light': 'Elbphilharmonie', 'theme.neutral': 'Prairie Tower',
|
|
670
|
+
'theme.default': 'Default', 'theme.dark': 'Sunset', 'theme.light': 'Elbphilharmonie', 'theme.neutral': 'Prairie Tower', 'theme.mono': 'Monochrome',
|
|
674
671
|
'theme.panelTitle': 'Choose theme', 'theme.close': 'Close',
|
|
675
672
|
'repo': 'Repo',
|
|
676
673
|
'donateTitle': 'Support', 'donateThanks': 'Thanks for your support ☕',
|
|
@@ -767,6 +764,8 @@
|
|
|
767
764
|
<script src="../qrcode.min.js"></script>
|
|
768
765
|
<script src="../i18n.js"></script>
|
|
769
766
|
<script src="../theme.js"></script>
|
|
767
|
+
<script src="../vendor/gsap/gsap.min.js"></script>
|
|
768
|
+
<script src="../motion.js"></script>
|
|
770
769
|
<script src="../admin.js"></script>
|
|
771
770
|
</body>
|
|
772
771
|
</html>
|
package/public/admin.js
CHANGED
|
@@ -935,10 +935,11 @@ function renderLangBtn() {
|
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
const THEME_META = [
|
|
938
|
-
{ id: 'default', sw: ['#
|
|
939
|
-
{ id: 'dark', sw: ['#
|
|
940
|
-
{ id: 'light', sw: ['#
|
|
941
|
-
{ id: 'neutral', sw: ['#
|
|
938
|
+
{ id: 'default', sw: ['#0D1117', '#21262D', '#58A6FF'] },
|
|
939
|
+
{ id: 'dark', sw: ['#161316', '#302323', '#FFB86B'] },
|
|
940
|
+
{ id: 'light', sw: ['#F5F7F8', '#FFFFFF', '#176B87'] },
|
|
941
|
+
{ id: 'neutral', sw: ['#EEF1E8', '#FAFBF6', '#47643C'] },
|
|
942
|
+
{ id: 'mono', sw: ['#050505', '#333333', '#F5F5F5'] }
|
|
942
943
|
]
|
|
943
944
|
|
|
944
945
|
function renderThemeBtn() {
|
|
@@ -957,7 +958,7 @@ function renderThemeOptions() {
|
|
|
957
958
|
if (!box) return
|
|
958
959
|
const cur = window.DSHTheme.get()
|
|
959
960
|
box.innerHTML = THEME_META.map(m => `
|
|
960
|
-
<button class="theme-option ${m.id === cur ? 'current' : ''}" data-theme="${m.id}" title="${t('theme.' + m.id)}">
|
|
961
|
+
<button type="button" class="theme-option ${m.id === cur ? 'current' : ''}" data-theme="${m.id}" aria-pressed="${m.id === cur}" title="${t('theme.' + m.id)}">
|
|
961
962
|
<span class="theme-swatches">${m.sw.map(c => `<i style="background:${c}"></i>`).join('')}</span>
|
|
962
963
|
<span class="theme-name">${t('theme.' + m.id)}</span>
|
|
963
964
|
<span class="theme-check">${m.id === cur ? '✓' : ''}</span>
|
package/public/app.js
CHANGED
|
@@ -1673,6 +1673,24 @@ function goalOf(s) {
|
|
|
1673
1673
|
if (!p) return null
|
|
1674
1674
|
return p.goal && typeof p.goal === 'object' ? p.goal : p
|
|
1675
1675
|
}
|
|
1676
|
+
const COLLAPSED_GOALS_KEY = 'dshCollapsedGoalsV1'
|
|
1677
|
+
function collapsedGoals() {
|
|
1678
|
+
try {
|
|
1679
|
+
const value = JSON.parse(LS.get(COLLAPSED_GOALS_KEY, '[]'))
|
|
1680
|
+
return Array.isArray(value) ? value.filter(item => item && typeof item.sessionId === 'string' && typeof item.goalId === 'string') : []
|
|
1681
|
+
} catch { return [] }
|
|
1682
|
+
}
|
|
1683
|
+
function goalDisplayId(goal) { return String(goal?.id || '__current__') }
|
|
1684
|
+
function isGoalCollapsed(sessionId, goal) {
|
|
1685
|
+
const goalId = goalDisplayId(goal)
|
|
1686
|
+
return collapsedGoals().some(item => item.sessionId === sessionId && item.goalId === goalId)
|
|
1687
|
+
}
|
|
1688
|
+
function setGoalCollapsed(sessionId, goal, collapsed) {
|
|
1689
|
+
const goalId = goalDisplayId(goal)
|
|
1690
|
+
const next = collapsedGoals().filter(item => item.sessionId !== sessionId)
|
|
1691
|
+
if (collapsed) next.push({ sessionId, goalId })
|
|
1692
|
+
LS.set(COLLAPSED_GOALS_KEY, JSON.stringify(next.slice(-100)))
|
|
1693
|
+
}
|
|
1676
1694
|
|
|
1677
1695
|
function updatePendingBadge() {
|
|
1678
1696
|
const pending = state.approvals.length + state.questions.length
|
|
@@ -2684,15 +2702,23 @@ async function renderSessionCards() {
|
|
|
2684
2702
|
let html = ''
|
|
2685
2703
|
|
|
2686
2704
|
if (goal && !isGoalTerminal(goal)) {
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
<div
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
<
|
|
2694
|
-
<
|
|
2695
|
-
|
|
2705
|
+
const collapsed = isGoalCollapsed(sessionId, goal)
|
|
2706
|
+
html += `<div class="goal-disclosure${collapsed ? ' is-collapsed' : ''}">
|
|
2707
|
+
<div id="goal-panel-mobile" class="card goal-card${collapsed ? ' hidden' : ''}">
|
|
2708
|
+
<div class="goal-card-head"><div class="card-title">${t('goal.title')}</div>
|
|
2709
|
+
<button type="button" class="goal-collapse-btn" data-goal-collapse="1" aria-expanded="true" aria-controls="goal-panel-mobile" title="${esc(t('goal.collapse'))}"><span aria-hidden="true">›</span>${t('goal.collapseShort')}</button>
|
|
2710
|
+
</div>
|
|
2711
|
+
<div class="goal-obj">${esc(goal.objective || '')}</div>
|
|
2712
|
+
<div class="goal-phase">phase: ${esc(goal.phase || '?')} · revision ${goal.revision ?? '?'}</div>
|
|
2713
|
+
<div class="goal-actions">
|
|
2714
|
+
${goal.phase === 'active' ? '<button class="mini-btn" data-goal="pause">' + t('goal.pause') + '</button>' : '<button class="mini-btn" data-goal="resume">' + t('goal.resume') + '</button>'}
|
|
2715
|
+
<button class="mini-btn" data-goal="complete">${t('goal.complete')}</button>
|
|
2716
|
+
<button class="mini-btn" data-goal="edit">${t('goal.edit')}</button>
|
|
2717
|
+
<button class="mini-btn" data-goal="clear">${t('goal.clear')}</button>
|
|
2718
|
+
</div>
|
|
2719
|
+
</div>
|
|
2720
|
+
<button type="button" class="goal-side-tab${collapsed ? '' : ' hidden'}" data-goal-collapse="0" aria-expanded="false" aria-controls="goal-panel-mobile" aria-label="${esc(t('goal.expand'))}" title="${esc(t('goal.expand'))}"><span aria-hidden="true">‹</span><span>${t('goal.title')}</span><small>${t('goal.collapsedHint')}</small></button>
|
|
2721
|
+
</div>`
|
|
2696
2722
|
}
|
|
2697
2723
|
if (todos?.items?.length) {
|
|
2698
2724
|
html += `<div class="card"><div class="card-title">${t('todos.title')}</div>${todos.items.map(t =>
|
|
@@ -2702,6 +2728,15 @@ async function renderSessionCards() {
|
|
|
2702
2728
|
box.innerHTML = html
|
|
2703
2729
|
box.querySelectorAll('[data-goal]').forEach(btn =>
|
|
2704
2730
|
btn.addEventListener('click', () => goalAction(btn.dataset.goal)))
|
|
2731
|
+
box.querySelectorAll('[data-goal-collapse]').forEach(btn =>
|
|
2732
|
+
btn.addEventListener('click', () => {
|
|
2733
|
+
const collapse = btn.dataset.goalCollapse === '1'
|
|
2734
|
+
const currentGoal = goalOf(state.byId.get(state.current))
|
|
2735
|
+
if (!currentGoal) return
|
|
2736
|
+
setGoalCollapsed(state.current, currentGoal, collapse)
|
|
2737
|
+
void renderSessionCards()
|
|
2738
|
+
requestAnimationFrame(() => box.querySelector(`[data-goal-collapse="${collapse ? '0' : '1'}"]`)?.focus())
|
|
2739
|
+
}))
|
|
2705
2740
|
|
|
2706
2741
|
// 子代理
|
|
2707
2742
|
const sub = await safeRpc('subagent.list', { parentSessionId: sessionId })
|
|
@@ -5728,6 +5763,8 @@ function showView(id) {
|
|
|
5728
5763
|
// 离开会话页必须清掉 in-session, 否则其他页面顶栏被 body 样式隐藏
|
|
5729
5764
|
document.body.classList.toggle('in-session', id === 'view-session')
|
|
5730
5765
|
document.querySelectorAll('.nav-btn').forEach(b => b.classList.toggle('active', b.dataset.view === id))
|
|
5766
|
+
// 主页已有上下文明确的刷新按钮,避免顶栏出现第二个同义入口。
|
|
5767
|
+
$('btn-refresh')?.classList.toggle('hidden', id === 'view-activity')
|
|
5731
5768
|
window.DshMotion?.view($(id))
|
|
5732
5769
|
window.scrollTo(0, 0)
|
|
5733
5770
|
if (id === 'view-files' && !state.fs.loaded) {
|
|
@@ -6411,10 +6448,11 @@ function renderLangBtn() {
|
|
|
6411
6448
|
}
|
|
6412
6449
|
|
|
6413
6450
|
const THEME_META = [
|
|
6414
|
-
{ id: 'default', sw: ['#
|
|
6415
|
-
{ id: 'dark', sw: ['#
|
|
6416
|
-
{ id: 'light', sw: ['#
|
|
6417
|
-
{ id: 'neutral', sw: ['#
|
|
6451
|
+
{ id: 'default', sw: ['#0D1117', '#21262D', '#58A6FF'] },
|
|
6452
|
+
{ id: 'dark', sw: ['#161316', '#302323', '#FFB86B'] },
|
|
6453
|
+
{ id: 'light', sw: ['#F5F7F8', '#FFFFFF', '#176B87'] },
|
|
6454
|
+
{ id: 'neutral', sw: ['#EEF1E8', '#FAFBF6', '#47643C'] },
|
|
6455
|
+
{ id: 'mono', sw: ['#050505', '#333333', '#F5F5F5'] }
|
|
6418
6456
|
]
|
|
6419
6457
|
|
|
6420
6458
|
function renderThemeBtn() {
|
|
@@ -6427,7 +6465,7 @@ function renderThemeOptions() {
|
|
|
6427
6465
|
if (!box) return
|
|
6428
6466
|
const cur = window.DSHTheme.get()
|
|
6429
6467
|
box.innerHTML = THEME_META.map(m => `
|
|
6430
|
-
<button class="theme-option ${m.id === cur ? 'current' : ''}" data-theme="${m.id}" title="${t('theme.' + m.id)}">
|
|
6468
|
+
<button type="button" class="theme-option ${m.id === cur ? 'current' : ''}" data-theme="${m.id}" aria-pressed="${m.id === cur}" title="${t('theme.' + m.id)}">
|
|
6431
6469
|
<span class="theme-swatches">${m.sw.map(c => `<i style="background:${c}"></i>`).join('')}</span>
|
|
6432
6470
|
<span class="theme-name">${t('theme.' + m.id)}</span>
|
|
6433
6471
|
<span class="theme-check">${m.id === cur ? '✓' : ''}</span>
|
|
@@ -8,6 +8,7 @@ html, body {
|
|
|
8
8
|
.hidden { display: none !important; }
|
|
9
9
|
.ds-app { position: fixed; inset: 0; display: flex; overflow: hidden; }
|
|
10
10
|
.ds-sidebar { width: 280px; flex: none; display: flex; flex-direction: column; border-right: 1px solid var(--dsr-line); background: linear-gradient(180deg, var(--dsr-panel), var(--dsr-bg)); box-shadow: 12px 0 34px var(--dsr-shadow); overflow: hidden; }
|
|
11
|
+
.ds-sidebar-backdrop { display: none; }
|
|
11
12
|
.ds-brand { display: flex; align-items: center; gap: 8px; padding: 17px 18px 12px; font-weight: 750; font-size: 15px; letter-spacing: .1px; }
|
|
12
13
|
.ds-logo { color: var(--dsr-accent-strong); }
|
|
13
14
|
.ds-brand-name { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
@@ -288,7 +289,30 @@ button.ds-overview-attention-item, button.ds-overview-session-item { cursor:poin
|
|
|
288
289
|
.ds-session-cards:empty { display: none; }
|
|
289
290
|
.ds-card { background: var(--dsr-panel); border: 1px solid var(--dsr-line); border-radius: 12px; padding: 10px 12px; }
|
|
290
291
|
.ds-card-title { font-size: 11px; font-weight: 700; color: var(--dsr-muted); letter-spacing: .6px; margin-bottom: 6px; text-transform: uppercase; }
|
|
291
|
-
.ds-goal-
|
|
292
|
+
.ds-goal-disclosure { width: 100%; min-width: 0; display: flex; justify-content: flex-end; }
|
|
293
|
+
.ds-goal-disclosure .ds-goal-card { width: 100%; min-width: 0; }
|
|
294
|
+
.ds-goal-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
|
|
295
|
+
.ds-goal-card-head .ds-card-title { min-width: 0; margin-bottom: 0; }
|
|
296
|
+
.ds-goal-collapse-btn,
|
|
297
|
+
.ds-goal-side-tab {
|
|
298
|
+
touch-action: manipulation; border: 1px solid var(--dsr-line); background: var(--dsr-bg-2); color: var(--dsr-muted);
|
|
299
|
+
font: inherit; cursor: pointer;
|
|
300
|
+
}
|
|
301
|
+
.ds-goal-collapse-btn { min-height: 32px; display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 8px; font-size: 11.5px; }
|
|
302
|
+
.ds-goal-collapse-btn > span { color: var(--dsr-accent-strong); font-size: 17px; line-height: 1; }
|
|
303
|
+
.ds-goal-side-tab {
|
|
304
|
+
min-height: 42px; max-width: min(100%, 210px); display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px 6px 10px;
|
|
305
|
+
border-right: 0; border-radius: 11px 0 0 11px; box-shadow: -5px 6px 18px var(--dsr-shadow); color: var(--dsr-text); font-size: 12px; font-weight: 700;
|
|
306
|
+
}
|
|
307
|
+
.ds-goal-side-tab > span:first-child { color: var(--dsr-accent-strong); font-size: 19px; line-height: 1; }
|
|
308
|
+
.ds-goal-side-tab small { min-width: 0; color: var(--dsr-muted); font-size: 10.5px; font-weight: 500; white-space: nowrap; }
|
|
309
|
+
.ds-goal-collapse-btn:hover,
|
|
310
|
+
.ds-goal-side-tab:hover { background: var(--dsr-panel-2); color: var(--dsr-text); }
|
|
311
|
+
.ds-goal-collapse-btn:active,
|
|
312
|
+
.ds-goal-side-tab:active { transform: translateY(1px); }
|
|
313
|
+
.ds-goal-collapse-btn:focus-visible,
|
|
314
|
+
.ds-goal-side-tab:focus-visible { outline: 2px solid var(--dsr-accent-strong); outline-offset: 2px; }
|
|
315
|
+
.ds-goal-obj { font-size: 13px; line-height: 1.55; word-break: break-word; overflow-wrap: anywhere; }
|
|
292
316
|
.ds-goal-phase { font-size: 11px; color: var(--dsr-muted); margin-top: 3px; }
|
|
293
317
|
.ds-goal-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
|
|
294
318
|
.ds-mini-btn { display: inline-flex; align-items: center; justify-content: center; min-height: 26px; padding: 2px 9px; border-radius: 7px; background: var(--dsr-bg-2); border: 1px solid var(--dsr-line); color: var(--dsr-text); font: inherit; font-size: 11.5px; cursor: pointer; }
|
|
@@ -350,6 +374,10 @@ button.ds-overview-attention-item, button.ds-overview-session-item { cursor:poin
|
|
|
350
374
|
.ds-settings { max-width: 720px; display: flex; flex-direction: column; gap: 10px; }
|
|
351
375
|
.ds-setting-row { display: flex; align-items: center; gap: 10px; background: var(--dsr-panel); border: 1px solid var(--dsr-line); border-radius: 12px; padding: 10px 14px; }
|
|
352
376
|
.ds-setting-row > div:first-child { flex: 1; min-width: 0; }
|
|
377
|
+
.ds-setting-link { width: 100%; color: var(--dsr-text); font: inherit; text-align: left; cursor: pointer; transition: background-color .18s ease, border-color .18s ease; }
|
|
378
|
+
.ds-setting-link:hover, .ds-setting-link:focus-visible { background: var(--dsr-bg-2); border-color: var(--dsr-accent-line); }
|
|
379
|
+
.ds-setting-link .ds-setting-arrow { transition: transform .18s ease, color .18s ease; }
|
|
380
|
+
.ds-setting-link:hover .ds-setting-arrow, .ds-setting-link:focus-visible .ds-setting-arrow { color: var(--dsr-accent-strong); transform: translateX(2px); }
|
|
353
381
|
.ds-setting-arrow,
|
|
354
382
|
#settings-home .ds-setting-row .ds-btn {
|
|
355
383
|
display: inline-flex; align-items: center; justify-content: center;
|
|
@@ -397,8 +425,8 @@ button.ds-overview-attention-item, button.ds-overview-session-item { cursor:poin
|
|
|
397
425
|
.ds-mini:hover { color: var(--dsr-text); }
|
|
398
426
|
.ds-switch { position: relative; display: inline-block; width: 36px; height: 21px; flex-shrink: 0; }
|
|
399
427
|
.ds-switch input { opacity: 0; width: 0; height: 0; }
|
|
400
|
-
.ds-switch .ds-slider { position: absolute; inset: 0; border-radius: 999px; background: var(--dsr-panel-2); border: 1px solid var(--dsr-line); transition: .2s; }
|
|
401
|
-
.ds-switch .ds-slider::before { content: ''; position: absolute; width: 15px; height: 15px; border-radius: 50%; left: 2px; top: 2px; background: var(--dsr-muted); transition: .2s; }
|
|
428
|
+
.ds-switch .ds-slider { position: absolute; inset: 0; border-radius: 999px; background: var(--dsr-panel-2); border: 1px solid var(--dsr-line); transition: background-color .2s ease, border-color .2s ease; }
|
|
429
|
+
.ds-switch .ds-slider::before { content: ''; position: absolute; width: 15px; height: 15px; border-radius: 50%; left: 2px; top: 2px; background: var(--dsr-muted); transition: transform .2s ease, background-color .2s ease; }
|
|
402
430
|
.ds-switch input:checked + .ds-slider { background: var(--dsr-accent-soft); border-color: var(--dsr-accent); }
|
|
403
431
|
.ds-switch input:checked + .ds-slider::before { transform: translateX(15px); background: var(--dsr-accent); }
|
|
404
432
|
|
|
@@ -429,7 +457,7 @@ button.ds-overview-attention-item, button.ds-overview-session-item { cursor:poin
|
|
|
429
457
|
.ds-stats-note { font-size: 11px; color: var(--dsr-muted); line-height: 1.6; margin-top: 8px; }
|
|
430
458
|
|
|
431
459
|
/* 统计抽屉(右侧滑出) */
|
|
432
|
-
.ds-drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 110; width: min(540px, 100vw); background: var(--dsr-panel); border-left: 1px solid var(--dsr-line); box-shadow: -12px 0 32px rgba(0,0,0,.35); display: flex; flex-direction: column; }
|
|
460
|
+
.ds-drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 110; width: min(540px, 100vw); background: var(--dsr-panel); border-left: 1px solid var(--dsr-line); box-shadow: -12px 0 32px rgba(0,0,0,.35); display: flex; flex-direction: column; overscroll-behavior: contain; }
|
|
433
461
|
.ds-drawer.hidden { display: none; }
|
|
434
462
|
.ds-drawer-head { flex: none; display: flex; align-items: center; justify-content: space-between; padding: 13px 15px; border-bottom: 1px solid var(--dsr-line); font-weight: 700; font-size: 15px; }
|
|
435
463
|
.ds-drawer-body { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 15px; scrollbar-width: thin; scrollbar-color: var(--dsr-line) transparent; }
|
|
@@ -453,7 +481,7 @@ button.ds-overview-attention-item, button.ds-overview-session-item { cursor:poin
|
|
|
453
481
|
/* 模态 */
|
|
454
482
|
.ds-modal { position: fixed; inset: 0; z-index: 120; background: rgba(0,0,0,.5); display: flex; align-items: center; justify-content: center; padding: 16px; }
|
|
455
483
|
.ds-modal.hidden { display: none; }
|
|
456
|
-
.ds-modal-card { width: min(520px, 100%); background: var(--dsr-panel); border: 1px solid var(--dsr-line); border-radius:
|
|
484
|
+
.ds-modal-card { width: min(520px, 100%); background: var(--dsr-panel); border: 1px solid var(--dsr-line); border-radius: 18px; padding: 18px; box-shadow: 0 22px 60px var(--dsr-shadow); overscroll-behavior: contain; }
|
|
457
485
|
.ds-modal-title { font-weight: 700; margin-bottom: 10px; }
|
|
458
486
|
.ds-modal-body { display: flex; flex-direction: column; gap: 10px; max-height: 60vh; overflow-y: auto; }
|
|
459
487
|
.ds-workspace-create-desc { margin: 0; color: var(--dsr-muted); line-height: 1.55; }
|
|
@@ -529,9 +557,22 @@ input:focus-visible, select:focus-visible, textarea:focus-visible {
|
|
|
529
557
|
.ds-btn:hover { filter: brightness(1.08); }
|
|
530
558
|
}
|
|
531
559
|
|
|
532
|
-
/* 窄屏回退:
|
|
560
|
+
/* 窄屏回退: 侧栏变为可关闭抽屉,保留完整导航与会话上下文。 */
|
|
533
561
|
@media (max-width: 1023px) {
|
|
534
|
-
.ds-sidebar {
|
|
562
|
+
.ds-sidebar {
|
|
563
|
+
position: fixed; inset: 0 auto 0 0; z-index: 90; display: flex;
|
|
564
|
+
width: min(320px, 86vw); max-width: 100%;
|
|
565
|
+
opacity: 0; pointer-events: none; transform: translateX(-104%);
|
|
566
|
+
transition: transform .24s ease, opacity .18s ease;
|
|
567
|
+
box-shadow: 18px 0 48px rgba(0,0,0,.38);
|
|
568
|
+
}
|
|
569
|
+
.ds-sidebar.mobile-open { opacity: 1; pointer-events: auto; transform: translateX(0); }
|
|
570
|
+
.ds-sidebar-backdrop {
|
|
571
|
+
position: fixed; inset: 0; z-index: 80; display: block;
|
|
572
|
+
border: 0; background: var(--dsr-overlay); cursor: default;
|
|
573
|
+
}
|
|
574
|
+
.ds-sidebar-backdrop.hidden { display: none; }
|
|
575
|
+
.ds-app.mobile-nav-open { overflow: hidden; }
|
|
535
576
|
#btn-mobile-nav { display: inline-flex; }
|
|
536
577
|
.ds-content { flex-direction: column; }
|
|
537
578
|
.ds-view { padding: 10px; overflow-y: auto; }
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>DSH Remote · 桌面</title>
|
|
7
|
-
<script>/* 首帧前应用皮肤 */ (function(){try{var t=localStorage.getItem('dshTheme');if(t!=='default'&&t!=='dark'&&t!=='light'&&t!=='neutral'){t=window.matchMedia('(prefers-color-scheme: light)').matches?'light':'default'}document.documentElement.setAttribute('data-theme',t)}catch(e){}})()</script>
|
|
7
|
+
<script>/* 首帧前应用皮肤 */ (function(){try{var t=localStorage.getItem('dshTheme');if(t!=='default'&&t!=='dark'&&t!=='light'&&t!=='neutral'&&t!=='mono'){t=window.matchMedia('(prefers-color-scheme: light)').matches?'light':'default'}document.documentElement.setAttribute('data-theme',t)}catch(e){}})()</script>
|
|
8
8
|
<link rel="stylesheet" href="../theme-vars.css">
|
|
9
9
|
<link rel="stylesheet" href="desktop.css">
|
|
10
10
|
</head>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
</div>
|
|
51
51
|
<button class="ds-nav-item" data-view="view-overview"><span class="ds-nav-ico">◌</span><span data-i18n="ds.overview">主页</span></button>
|
|
52
52
|
<button class="ds-nav-item" data-view="view-files"><span class="ds-nav-ico">⇅</span><span data-i18n="ds.files">文件传输</span></button>
|
|
53
|
-
<button class="ds-nav-item" data-view="view-settings"><span class="ds-nav-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><
|
|
53
|
+
<button class="ds-nav-item" data-view="view-settings"><span class="ds-nav-ico"><svg class="settings-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.09a2 2 0 0 1 1 1.73v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.38a2 2 0 0 0-.73-2.73l-.15-.09a2 2 0 0 1-1-1.74v-.51a2 2 0 0 1 1-1.73l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2Z"/><circle cx="12" cy="12" r="3"/></svg></span><span data-i18n="ds.settings">设置</span></button>
|
|
54
54
|
<div class="ds-feedback">
|
|
55
55
|
<button id="btn-feedback" class="ds-feedback-btn" aria-haspopup="menu" aria-expanded="false" data-i18n-title="ds.feedback" data-i18n-aria="ds.feedback">
|
|
56
56
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8 8 0 0 1-8 8H5l-1.5 2L4 20a8 8 0 0 1-1-4 8 8 0 0 1 18-4Z"/></svg>
|
|
@@ -81,10 +81,11 @@
|
|
|
81
81
|
</div>
|
|
82
82
|
</div>
|
|
83
83
|
</aside>
|
|
84
|
+
<button id="ds-sidebar-backdrop" class="ds-sidebar-backdrop hidden" type="button" data-i18n-aria="ds.close" aria-label="关闭菜单"></button>
|
|
84
85
|
|
|
85
86
|
<div class="ds-main">
|
|
86
87
|
<header class="ds-topbar">
|
|
87
|
-
<button id="btn-mobile-nav" class="ds-icon-btn" data-i18n-aria="ds.menu" data-i18n-title="ds.menu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
|
88
|
+
<button id="btn-mobile-nav" class="ds-icon-btn" aria-controls="ds-sidebar" aria-expanded="false" data-i18n-aria="ds.menu" data-i18n-title="ds.menu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
|
88
89
|
<div class="ds-title" id="ds-title" data-i18n="ds.sessions">会话</div>
|
|
89
90
|
<span id="ds-session-status" class="ds-session-status hidden"></span>
|
|
90
91
|
<button id="btn-rename-session" class="ds-icon-btn hidden" data-i18n-title="ds.sessionRename" data-i18n-aria="ds.sessionRename">✎</button>
|
|
@@ -202,22 +203,22 @@
|
|
|
202
203
|
<div class="ds-section-label" data-i18n="ds.settings">设置</div>
|
|
203
204
|
<div id="settings-home">
|
|
204
205
|
<div class="ds-settings">
|
|
205
|
-
<
|
|
206
|
+
<button type="button" class="ds-setting-row ds-setting-link" data-settings-group="general">
|
|
206
207
|
<div><div class="ds-setting-name" data-i18n="ds.groupGeneral">通用</div><div class="ds-setting-desc" data-i18n="ds.groupGeneralDesc">工具调用、预设提示词</div></div>
|
|
207
208
|
<span class="ds-setting-arrow" aria-hidden="true">›</span>
|
|
208
|
-
</
|
|
209
|
-
<
|
|
209
|
+
</button>
|
|
210
|
+
<button type="button" class="ds-setting-row ds-setting-link" data-settings-group="servers">
|
|
210
211
|
<div><div class="ds-setting-name" data-i18n="ds.groupServers">服务器</div><div class="ds-setting-desc" data-i18n="ds.groupServersDesc">服务器地址</div></div>
|
|
211
212
|
<span class="ds-setting-arrow" aria-hidden="true">›</span>
|
|
212
|
-
</
|
|
213
|
-
<
|
|
213
|
+
</button>
|
|
214
|
+
<button type="button" class="ds-setting-row ds-setting-link" data-settings-group="theme">
|
|
214
215
|
<div><div class="ds-setting-name" data-i18n="ds.groupTheme">皮肤</div><div class="ds-setting-desc" data-i18n="ds.groupThemeDesc">配色主题</div></div>
|
|
215
216
|
<span class="ds-setting-arrow" aria-hidden="true">›</span>
|
|
216
|
-
</
|
|
217
|
-
<
|
|
217
|
+
</button>
|
|
218
|
+
<button type="button" class="ds-setting-row ds-setting-link" data-settings-group="about">
|
|
218
219
|
<div><div class="ds-setting-name" data-i18n="ds.groupAbout">关于</div><div class="ds-setting-desc" data-i18n="ds.groupAboutDesc">版本信息</div></div>
|
|
219
220
|
<span class="ds-setting-arrow" aria-hidden="true">›</span>
|
|
220
|
-
</
|
|
221
|
+
</button>
|
|
221
222
|
</div>
|
|
222
223
|
<div class="ds-settings">
|
|
223
224
|
<div class="ds-setting-row">
|
|
@@ -231,7 +232,7 @@
|
|
|
231
232
|
</div>
|
|
232
233
|
</div>
|
|
233
234
|
|
|
234
|
-
<div id="settings-page-general" class="ds-settings hidden">
|
|
235
|
+
<div id="settings-page-general" class="ds-settings hidden" data-motion-panel>
|
|
235
236
|
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
236
237
|
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
237
238
|
<div class="ds-setting-name" data-i18n="ds.groupGeneral">通用</div>
|
|
@@ -242,7 +243,7 @@
|
|
|
242
243
|
</div>
|
|
243
244
|
</div>
|
|
244
245
|
|
|
245
|
-
<div id="settings-page-servers" class="ds-settings hidden">
|
|
246
|
+
<div id="settings-page-servers" class="ds-settings hidden" data-motion-panel>
|
|
246
247
|
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
247
248
|
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
248
249
|
<div class="ds-setting-name" data-i18n="ds.groupServers">服务器</div>
|
|
@@ -266,18 +267,18 @@
|
|
|
266
267
|
</div>
|
|
267
268
|
</div>
|
|
268
269
|
|
|
269
|
-
<div id="settings-page-theme" class="ds-settings hidden">
|
|
270
|
+
<div id="settings-page-theme" class="ds-settings hidden" data-motion-panel>
|
|
270
271
|
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
271
272
|
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
272
273
|
<div class="ds-setting-name" data-i18n="ds.groupTheme">皮肤</div>
|
|
273
274
|
</div>
|
|
274
275
|
<div class="ds-setting-row">
|
|
275
|
-
<div><div class="ds-setting-name" data-i18n="ds.themeTitle">皮肤</div><div class="ds-setting-desc" data-i18n="ds.themeDesc"
|
|
276
|
+
<div><div class="ds-setting-name" data-i18n="ds.themeTitle">皮肤</div><div class="ds-setting-desc" data-i18n="ds.themeDesc">五套皮肤</div></div>
|
|
276
277
|
<button id="btn-theme" class="ds-btn">默认深空</button>
|
|
277
278
|
</div>
|
|
278
279
|
</div>
|
|
279
280
|
|
|
280
|
-
<div id="settings-page-about" class="ds-settings hidden">
|
|
281
|
+
<div id="settings-page-about" class="ds-settings hidden" data-motion-panel>
|
|
281
282
|
<div class="ds-setting-row" data-settings-back style="cursor:pointer">
|
|
282
283
|
<button class="ds-btn" data-i18n="ds.back">‹ 返回</button>
|
|
283
284
|
<div class="ds-setting-name" data-i18n="ds.groupAbout">关于</div>
|
|
@@ -475,7 +476,7 @@
|
|
|
475
476
|
'ds.back': '‹ 返回', 'ds.emptyGroup': '暂无设置项',
|
|
476
477
|
'ds.serversTitle': '服务器(分组)', 'ds.speedTest': '测速', 'ds.currentGroup': '当前组',
|
|
477
478
|
'ds.addGroup': '+ 组', 'ds.addServer': '添加', 'ds.tokenTitle': '访问令牌', 'ds.copyToken': '复制',
|
|
478
|
-
'ds.themeTitle': '皮肤', 'ds.themeDesc': '默认深空 / 落日 / 易北爱乐厅 / 草原孤塔', 'ds.langTitle': '语言 / Language',
|
|
479
|
+
'ds.themeTitle': '皮肤', 'ds.themeDesc': '默认深空 / 落日 / 易北爱乐厅 / 草原孤塔 / 黑曜白', 'ds.langTitle': '语言 / Language',
|
|
479
480
|
'ds.feedbackTitle': '反馈渠道', 'ds.feedbackDesc': 'GitHub / Gitee / B站:反馈 bug、提建议、唠嗑',
|
|
480
481
|
'ds.feedback': '反馈', 'ds.feedbackGithubDesc': '反馈 bug / 提建议', 'ds.feedbackGiteeDesc': '国内镜像,无需代理',
|
|
481
482
|
'ds.feedbackBiliDesc': 'UP 动态页交流', 'ds.feedbackCopyLink': '复制项目链接', 'ds.feedbackCopyDesc': '手动分享给朋友',
|
|
@@ -526,7 +527,7 @@
|
|
|
526
527
|
'ds.groupsPromptRename': '重命名组「{group}」:', 'ds.groupsRenamed': '组已重命名',
|
|
527
528
|
'ds.groupsCannotDeleteDefault': '默认组不可删除',
|
|
528
529
|
'ds.groupsConfirmDelete': '删除组「{group}」?组内服务器将归入默认组。', 'ds.groupsDeleted': '组已删除',
|
|
529
|
-
'ds.theme.default': '默认深空', 'ds.theme.dark': '落日', 'ds.theme.light': '易北爱乐厅', 'ds.theme.neutral': '草原孤塔',
|
|
530
|
+
'ds.theme.default': '默认深空', 'ds.theme.dark': '落日', 'ds.theme.light': '易北爱乐厅', 'ds.theme.neutral': '草原孤塔', 'ds.theme.mono': '黑曜白',
|
|
530
531
|
'ds.role.me': '我', 'ds.role.dsh': 'DSH', 'ds.toolDefault': '工具',
|
|
531
532
|
'ds.eventSystemReminder': '系统提示',
|
|
532
533
|
'ds.questionOptions': '选项', 'ds.questionCustom': '自定义回答',
|
|
@@ -540,6 +541,7 @@
|
|
|
540
541
|
'presets.nameEmpty': '名称不能为空', 'presets.nameTooLong': '名称不能超过 20 字', 'presets.textTooLong': '内容不能超过 2000 字', 'presets.limit': '最多 20 条预设', 'presets.added': '预设已添加',
|
|
541
542
|
'presets.confirmDelete': '删除预设「{name}」?', 'presets.saved': '预设已保存', 'presets.deleted': '预设已删除',
|
|
542
543
|
'goal.title': '目标', 'goal.pause': '暂停', 'goal.resume': '继续', 'goal.complete': '完成', 'goal.edit': '改目标', 'goal.clear': '清除',
|
|
544
|
+
'goal.collapse': '收起目标到侧边', 'goal.collapseShort': '收起', 'goal.expand': '展开目标', 'goal.collapsedHint': '仍在运行',
|
|
543
545
|
'goal.none': '当前会话没有目标', 'goal.confirmClear': '清除当前目标?(不会删除会话)', 'goal.confirmComplete': '将目标标记为完成?',
|
|
544
546
|
'goal.actionFailed': '目标操作失败', 'goal.actionSubmitted': '目标操作已提交',
|
|
545
547
|
'goal.cannotEmpty': '目标不能为空', 'goal.updateFailed': '更新失败', 'goal.updated': '目标已更新', 'goal.editPrompt': '修改目标:',
|
|
@@ -577,7 +579,7 @@
|
|
|
577
579
|
'ds.back': '‹ Back', 'ds.emptyGroup': 'No settings here',
|
|
578
580
|
'ds.serversTitle': 'Servers (groups)', 'ds.speedTest': 'Test', 'ds.currentGroup': 'Current group',
|
|
579
581
|
'ds.addGroup': '+ Group', 'ds.addServer': 'Add', 'ds.tokenTitle': 'Access token', 'ds.copyToken': 'Copy',
|
|
580
|
-
'ds.themeTitle': 'Theme', 'ds.themeDesc': 'Deep Space / Sunset / Elbphilharmonie / Prairie Tower', 'ds.langTitle': 'Language',
|
|
582
|
+
'ds.themeTitle': 'Theme', 'ds.themeDesc': 'Deep Space / Sunset / Elbphilharmonie / Prairie Tower / Monochrome', 'ds.langTitle': 'Language',
|
|
581
583
|
'ds.feedbackTitle': 'Feedback', 'ds.feedbackDesc': 'GitHub / Gitee / Bilibili: report bugs, suggest features, or just chat',
|
|
582
584
|
'ds.feedback': 'Feedback', 'ds.feedbackGithubDesc': 'Report bugs · suggest features', 'ds.feedbackGiteeDesc': 'Mirror in China, no proxy needed',
|
|
583
585
|
'ds.feedbackBiliDesc': 'Chat on the UP\'s Bilibili page', 'ds.feedbackCopyLink': 'Copy project link', 'ds.feedbackCopyDesc': 'Share it manually',
|
|
@@ -628,7 +630,7 @@
|
|
|
628
630
|
'ds.groupsPromptRename': 'Rename group "{group}":', 'ds.groupsRenamed': 'Group renamed',
|
|
629
631
|
'ds.groupsCannotDeleteDefault': 'The default group cannot be deleted',
|
|
630
632
|
'ds.groupsConfirmDelete': 'Delete group "{group}"? Its servers move to the default group.', 'ds.groupsDeleted': 'Group deleted',
|
|
631
|
-
'ds.theme.default': 'Deep Space', 'ds.theme.dark': 'Sunset', 'ds.theme.light': 'Elbphilharmonie', 'ds.theme.neutral': 'Prairie Tower',
|
|
633
|
+
'ds.theme.default': 'Deep Space', 'ds.theme.dark': 'Sunset', 'ds.theme.light': 'Elbphilharmonie', 'ds.theme.neutral': 'Prairie Tower', 'ds.theme.mono': 'Monochrome',
|
|
632
634
|
'ds.role.me': 'Me', 'ds.role.dsh': 'DSH', 'ds.toolDefault': 'tool',
|
|
633
635
|
'ds.eventSystemReminder': 'System reminder',
|
|
634
636
|
'ds.questionOptions': 'Options', 'ds.questionCustom': 'Custom answer',
|
|
@@ -642,6 +644,7 @@
|
|
|
642
644
|
'presets.nameEmpty': 'Name cannot be empty', 'presets.nameTooLong': 'Name must be ≤20 characters', 'presets.textTooLong': 'Content must be ≤2000 characters', 'presets.limit': 'At most 20 presets', 'presets.added': 'Preset added',
|
|
643
645
|
'presets.confirmDelete': 'Delete preset "{name}"?', 'presets.saved': 'Preset saved', 'presets.deleted': 'Preset deleted',
|
|
644
646
|
'goal.title': 'Goal', 'goal.pause': 'Pause', 'goal.resume': 'Resume', 'goal.complete': 'Complete', 'goal.edit': 'Edit goal', 'goal.clear': 'Clear',
|
|
647
|
+
'goal.collapse': 'Collapse goal to the side', 'goal.collapseShort': 'Collapse', 'goal.expand': 'Expand goal', 'goal.collapsedHint': 'Still running',
|
|
645
648
|
'goal.none': 'This session has no goal', 'goal.confirmClear': 'Clear the current goal? (the session stays)', 'goal.confirmComplete': 'Mark the goal as completed?',
|
|
646
649
|
'goal.actionFailed': 'Goal action failed', 'goal.actionSubmitted': 'Goal action submitted',
|
|
647
650
|
'goal.cannotEmpty': 'Goal cannot be empty', 'goal.updateFailed': 'Update failed', 'goal.updated': 'Goal updated', 'goal.editPrompt': 'Edit goal:',
|