dsh-remote-plugin 0.4.4
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/README.md +34 -0
- package/client.js +140 -0
- package/cordis.patch.yml +4 -0
- package/gateway.cjs +675 -0
- package/index.mjs +392 -0
- package/package.json +56 -0
- package/public/admin.html +89 -0
- package/public/admin.js +265 -0
- package/public/app.js +1163 -0
- package/public/icon.svg +12 -0
- package/public/index.html +176 -0
- package/public/manifest.webmanifest +16 -0
- package/public/styles.css +396 -0
- package/public/update.json +6 -0
- package/public/version.json +3 -0
package/public/icon.svg
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#5b8cff"/>
|
|
5
|
+
<stop offset="1" stop-color="#b48cff"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="128" height="128" rx="28" fill="#0b0e1a"/>
|
|
9
|
+
<circle cx="64" cy="64" r="40" fill="none" stroke="url(#g)" stroke-width="10"/>
|
|
10
|
+
<path d="M64 24v22M64 82v22M24 64h22M82 64h22" stroke="url(#g)" stroke-width="10" stroke-linecap="round"/>
|
|
11
|
+
<circle cx="64" cy="64" r="12" fill="#7dcfff"/>
|
|
12
|
+
</svg>
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, user-scalable=no">
|
|
6
|
+
<meta name="theme-color" content="#0b0e1a">
|
|
7
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
8
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
9
|
+
<title>DSH Remote</title>
|
|
10
|
+
<link rel="manifest" href="manifest.webmanifest">
|
|
11
|
+
<link rel="icon" href="icon.svg" type="image/svg+xml">
|
|
12
|
+
<link rel="stylesheet" href="styles.css">
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<header class="topbar">
|
|
16
|
+
<div class="brand">
|
|
17
|
+
<span class="brand-dot"></span>
|
|
18
|
+
<span class="brand-name">DSH Remote</span>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="topbar-right">
|
|
21
|
+
<button id="btn-admin" class="icon-btn" title="主机管理" aria-label="主机管理">🖥</button>
|
|
22
|
+
<button id="btn-refresh" class="icon-btn" title="刷新" aria-label="刷新">⟳</button>
|
|
23
|
+
<span id="conn-badge" class="conn-badge off">未连接</span>
|
|
24
|
+
</div>
|
|
25
|
+
</header>
|
|
26
|
+
|
|
27
|
+
<main id="main" class="main">
|
|
28
|
+
<!-- 会话列表 -->
|
|
29
|
+
<section id="view-home" class="view">
|
|
30
|
+
<div class="stat-strip" id="stat-strip"></div>
|
|
31
|
+
<div class="section-head">
|
|
32
|
+
<span>会话</span>
|
|
33
|
+
<button id="btn-new-session" class="mini-btn">+ 新会话</button>
|
|
34
|
+
</div>
|
|
35
|
+
<div id="session-list" class="session-list"></div>
|
|
36
|
+
<div id="home-empty" class="empty hidden">暂无会话</div>
|
|
37
|
+
</section>
|
|
38
|
+
|
|
39
|
+
<!-- 会话详情 -->
|
|
40
|
+
<section id="view-session" class="view hidden">
|
|
41
|
+
<div class="session-head">
|
|
42
|
+
<button id="btn-back" class="icon-btn">‹</button>
|
|
43
|
+
<div class="session-head-meta">
|
|
44
|
+
<div id="session-title" class="session-title">加载中…</div>
|
|
45
|
+
<div id="session-sub" class="session-sub"></div>
|
|
46
|
+
</div>
|
|
47
|
+
<button id="btn-stats" class="icon-btn" title="本轮统计">📊</button>
|
|
48
|
+
<button id="btn-cancel" class="danger-btn hidden">停止</button>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div id="session-cards" class="cards"></div>
|
|
52
|
+
|
|
53
|
+
<div class="section-head small">
|
|
54
|
+
<span>对话</span>
|
|
55
|
+
<span id="history-hint" class="muted"></span>
|
|
56
|
+
</div>
|
|
57
|
+
<div id="history-wrap" class="history-wrap">
|
|
58
|
+
<div id="history" class="history"></div>
|
|
59
|
+
<div id="history-rail" class="history-rail">
|
|
60
|
+
<div class="rail-track"></div>
|
|
61
|
+
<div id="rail-thumb" class="rail-thumb"></div>
|
|
62
|
+
<div id="rail-nodes" class="rail-nodes"></div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div class="composer">
|
|
67
|
+
<textarea id="composer-input" rows="1" placeholder="给 DSH 发消息…(回车发送,Shift+Enter 换行)"></textarea>
|
|
68
|
+
<button id="btn-send" class="send-btn">发送</button>
|
|
69
|
+
</div>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
<!-- 待办 -->
|
|
73
|
+
<section id="view-activity" class="view hidden">
|
|
74
|
+
<div class="section-head"><span>待处理</span><span id="pending-count" class="muted"></span></div>
|
|
75
|
+
<div id="pending-list" class="pending-list"></div>
|
|
76
|
+
<div class="section-head"><span>后台任务</span></div>
|
|
77
|
+
<div id="jobs-list" class="jobs-list"></div>
|
|
78
|
+
</section>
|
|
79
|
+
|
|
80
|
+
<!-- 设置 -->
|
|
81
|
+
<section id="view-settings" class="view hidden">
|
|
82
|
+
<div class="settings-group">
|
|
83
|
+
<div class="setting-row">
|
|
84
|
+
<div><div class="setting-name">服务器地址</div><div class="setting-desc" id="server-desc">默认 = 当前页面地址</div></div>
|
|
85
|
+
<button id="btn-change-server" class="mini-btn">设置</button>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="setting-row">
|
|
88
|
+
<div><div class="setting-name">通知</div><div class="setting-desc">收到审批/提问时推送</div></div>
|
|
89
|
+
<label class="switch"><input type="checkbox" id="opt-notify"><span class="slider"></span></label>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="setting-row">
|
|
92
|
+
<div><div class="setting-name">显示工具调用</div><div class="setting-desc">关闭后隐藏 🔧/📦 工具调用与结果</div></div>
|
|
93
|
+
<label class="switch"><input type="checkbox" id="opt-tools"><span class="slider"></span></label>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="setting-row">
|
|
96
|
+
<div><div class="setting-name">访问令牌</div><div class="setting-desc" id="token-desc">已保存</div></div>
|
|
97
|
+
<button id="btn-change-token" class="mini-btn">更换</button>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="setting-row">
|
|
100
|
+
<div><div class="setting-name">DSH 状态</div><div class="setting-desc" id="host-desc">探测中…</div></div>
|
|
101
|
+
<button id="btn-host-describe" class="mini-btn">探测</button>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="setting-row">
|
|
104
|
+
<div><div class="setting-name">检查更新</div><div class="setting-desc" id="update-desc">加载中…</div>
|
|
105
|
+
<button id="btn-download-update" class="mini-btn hidden" style="margin-top:6px">下载并安装更新</button></div>
|
|
106
|
+
<button id="btn-check-update" class="mini-btn">检查</button>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
<div class="settings-group">
|
|
110
|
+
<div class="setting-row">
|
|
111
|
+
<div><div class="setting-name">清空本地数据</div><div class="setting-desc">令牌与缓存</div></div>
|
|
112
|
+
<button id="btn-reset" class="mini-btn">重置</button>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
<p class="about">DSH Remote · 局域网 / Tailscale 均可访问<br>仅作为 DSH 本机 3080 端口的带认证代理</p>
|
|
116
|
+
</section>
|
|
117
|
+
</main>
|
|
118
|
+
|
|
119
|
+
<nav class="bottom-nav">
|
|
120
|
+
<button data-view="view-home" class="nav-btn active"><span class="nav-ico">▤</span><span>会话</span></button>
|
|
121
|
+
<button data-view="view-activity" class="nav-btn"><span class="nav-ico">◷</span><span>待办<b id="nav-pending" class="nav-badge hidden"></b></span></button>
|
|
122
|
+
<button data-view="view-settings" class="nav-btn"><span class="nav-ico">⚙</span><span>设置</span></button>
|
|
123
|
+
</nav>
|
|
124
|
+
|
|
125
|
+
<!-- 审批模态 -->
|
|
126
|
+
<div id="modal-approval" class="modal hidden">
|
|
127
|
+
<div class="modal-card">
|
|
128
|
+
<div class="modal-title">工具审批</div>
|
|
129
|
+
<div id="approval-body" class="modal-body"></div>
|
|
130
|
+
<div class="modal-actions">
|
|
131
|
+
<button id="approval-reject" class="btn subtle">拒绝</button>
|
|
132
|
+
<button id="approval-allow" class="btn primary">允许一次</button>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<!-- 提问模态 -->
|
|
138
|
+
<div id="modal-question" class="modal hidden">
|
|
139
|
+
<div class="modal-card">
|
|
140
|
+
<div class="modal-title">DSH 需要你回答</div>
|
|
141
|
+
<div id="question-body" class="modal-body"></div>
|
|
142
|
+
<div class="modal-actions">
|
|
143
|
+
<button id="question-later" class="btn subtle">稍后</button>
|
|
144
|
+
<button id="question-submit" class="btn primary">提交</button>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<!-- goal 模态 -->
|
|
150
|
+
<div id="modal-goal" class="modal hidden">
|
|
151
|
+
<div class="modal-card">
|
|
152
|
+
<div class="modal-title">目标控制</div>
|
|
153
|
+
<div id="goal-body" class="modal-body"></div>
|
|
154
|
+
<div class="modal-actions">
|
|
155
|
+
<button id="goal-close" class="btn subtle">关闭</button>
|
|
156
|
+
<button id="goal-edit" class="btn primary hidden">更新目标</button>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<!-- 统计模态 -->
|
|
162
|
+
<div id="modal-stats" class="modal hidden">
|
|
163
|
+
<div class="modal-card">
|
|
164
|
+
<div class="modal-title">本轮统计</div>
|
|
165
|
+
<div id="stats-body" class="modal-body"></div>
|
|
166
|
+
<div class="modal-actions">
|
|
167
|
+
<button id="stats-close" class="btn subtle">关闭</button>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div id="toast" class="toast hidden"></div>
|
|
173
|
+
|
|
174
|
+
<script src="app.js"></script>
|
|
175
|
+
</body>
|
|
176
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "DSH Remote",
|
|
3
|
+
"short_name": "DSH Remote",
|
|
4
|
+
"start_url": "/",
|
|
5
|
+
"display": "standalone",
|
|
6
|
+
"background_color": "#0b0e1a",
|
|
7
|
+
"theme_color": "#0b0e1a",
|
|
8
|
+
"icons": [
|
|
9
|
+
{
|
|
10
|
+
"src": "icon.svg",
|
|
11
|
+
"sizes": "any",
|
|
12
|
+
"type": "image/svg+xml",
|
|
13
|
+
"purpose": "any"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/* DSH Remote · 移动优先深色蓝紫主题(红绿色弱友好: 蓝/青 + 橙/紫) */
|
|
2
|
+
:root {
|
|
3
|
+
--bg: #0b0e1a;
|
|
4
|
+
--bg-2: #101528;
|
|
5
|
+
--panel: #151b33;
|
|
6
|
+
--panel-2: #1b2340;
|
|
7
|
+
--line: #263056;
|
|
8
|
+
--text: #e8ecff;
|
|
9
|
+
--muted: #8b94bd;
|
|
10
|
+
--blue: #5b8cff;
|
|
11
|
+
--cyan: #7dcfff;
|
|
12
|
+
--orange: #ff9e64;
|
|
13
|
+
--purple: #b48cff;
|
|
14
|
+
--danger: #ff8f6b;
|
|
15
|
+
--ok: #7dcfff;
|
|
16
|
+
--radius: 14px;
|
|
17
|
+
--safe-top: max(env(safe-area-inset-top, 0px), var(--native-top, 0px));
|
|
18
|
+
--safe-b: max(env(safe-area-inset-bottom, 0px), var(--native-bottom, 0px));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
|
|
22
|
+
|
|
23
|
+
html, body {
|
|
24
|
+
margin: 0;
|
|
25
|
+
padding: 0;
|
|
26
|
+
background: var(--bg);
|
|
27
|
+
color: var(--text);
|
|
28
|
+
font-family: system-ui, -apple-system, "PingFang SC", "Noto Sans CJK SC", sans-serif;
|
|
29
|
+
font-size: 15px;
|
|
30
|
+
line-height: 1.5;
|
|
31
|
+
overscroll-behavior-y: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
body { padding-bottom: calc(64px + var(--safe-b)); }
|
|
35
|
+
|
|
36
|
+
.hidden { display: none !important; }
|
|
37
|
+
.muted { color: var(--muted); font-size: 12px; }
|
|
38
|
+
|
|
39
|
+
/* ---------- 顶栏 ---------- */
|
|
40
|
+
.topbar {
|
|
41
|
+
position: sticky; top: 0; z-index: 30;
|
|
42
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
43
|
+
padding: calc(var(--safe-top) + 10px) 14px 10px;
|
|
44
|
+
/* 实色背景: 小米/MIUI WebView 后台恢复时 backdrop-filter 图层会丢, 顶栏整块消失 */
|
|
45
|
+
background: var(--bg);
|
|
46
|
+
border-bottom: 1px solid var(--line);
|
|
47
|
+
}
|
|
48
|
+
.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; letter-spacing: .5px; }
|
|
49
|
+
.brand-dot {
|
|
50
|
+
width: 10px; height: 10px; border-radius: 50%;
|
|
51
|
+
background: linear-gradient(135deg, var(--blue), var(--purple));
|
|
52
|
+
box-shadow: 0 0 12px rgba(91, 140, 255, .8);
|
|
53
|
+
}
|
|
54
|
+
.topbar-right { display: flex; align-items: center; gap: 8px; }
|
|
55
|
+
.conn-badge {
|
|
56
|
+
font-size: 12px; padding: 3px 9px; border-radius: 999px;
|
|
57
|
+
border: 1px solid var(--line); color: var(--muted);
|
|
58
|
+
}
|
|
59
|
+
.conn-badge.on { color: var(--cyan); border-color: rgba(125, 207, 255, .45); background: rgba(125, 207, 255, .08); }
|
|
60
|
+
.conn-badge.off { color: var(--orange); border-color: rgba(255, 158, 100, .45); background: rgba(255, 158, 100, .08); }
|
|
61
|
+
|
|
62
|
+
/* ---------- 按钮 ---------- */
|
|
63
|
+
button {
|
|
64
|
+
font: inherit; color: inherit; background: none; border: none; cursor: pointer;
|
|
65
|
+
touch-action: manipulation;
|
|
66
|
+
}
|
|
67
|
+
.icon-btn {
|
|
68
|
+
width: 34px; height: 34px; border-radius: 10px;
|
|
69
|
+
background: var(--panel); border: 1px solid var(--line);
|
|
70
|
+
font-size: 17px; display: grid; place-items: center;
|
|
71
|
+
}
|
|
72
|
+
.icon-btn:active { background: var(--panel-2); }
|
|
73
|
+
.mini-btn {
|
|
74
|
+
padding: 5px 11px; border-radius: 9px; font-size: 13px;
|
|
75
|
+
background: var(--panel); border: 1px solid var(--line); color: var(--cyan);
|
|
76
|
+
}
|
|
77
|
+
.mini-btn:active { background: var(--panel-2); }
|
|
78
|
+
.btn {
|
|
79
|
+
flex: 1; padding: 11px 14px; border-radius: 12px; font-size: 15px; font-weight: 600;
|
|
80
|
+
border: 1px solid var(--line);
|
|
81
|
+
}
|
|
82
|
+
.btn.primary { background: var(--blue); border-color: var(--blue); color: #fff; }
|
|
83
|
+
.btn.subtle { background: var(--panel); color: var(--muted); }
|
|
84
|
+
.danger-btn {
|
|
85
|
+
padding: 7px 13px; border-radius: 10px; font-size: 13px; font-weight: 600;
|
|
86
|
+
background: rgba(255, 143, 107, .14); color: var(--danger);
|
|
87
|
+
border: 1px solid rgba(255, 143, 107, .4);
|
|
88
|
+
}
|
|
89
|
+
.danger-btn:active { background: rgba(255, 143, 107, .25); }
|
|
90
|
+
|
|
91
|
+
/* ---------- 主体 ---------- */
|
|
92
|
+
.main { padding: 12px 12px 20px; max-width: 720px; margin: 0 auto; }
|
|
93
|
+
.view { animation: fadein .18s ease; }
|
|
94
|
+
@keyframes fadein { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; } }
|
|
95
|
+
|
|
96
|
+
.stat-strip {
|
|
97
|
+
display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px;
|
|
98
|
+
}
|
|
99
|
+
.stat {
|
|
100
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
|
101
|
+
padding: 10px 12px;
|
|
102
|
+
}
|
|
103
|
+
.stat .v { font-size: 21px; font-weight: 700; }
|
|
104
|
+
.stat .k { font-size: 11px; color: var(--muted); }
|
|
105
|
+
.stat.running .v { color: var(--orange); }
|
|
106
|
+
.stat.pending .v { color: var(--purple); }
|
|
107
|
+
.stat.ctx .v { color: var(--cyan); }
|
|
108
|
+
|
|
109
|
+
.section-head {
|
|
110
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
111
|
+
margin: 14px 2px 8px; font-size: 13px; font-weight: 700; color: var(--muted);
|
|
112
|
+
letter-spacing: 1px;
|
|
113
|
+
}
|
|
114
|
+
.section-head.small { margin-top: 6px; }
|
|
115
|
+
|
|
116
|
+
/* ---------- 会话列表 ---------- */
|
|
117
|
+
.session-list { display: flex; flex-direction: column; gap: 8px; }
|
|
118
|
+
.session-card {
|
|
119
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
|
120
|
+
padding: 12px 13px; position: relative; overflow: hidden;
|
|
121
|
+
}
|
|
122
|
+
.session-card:active { background: var(--panel-2); }
|
|
123
|
+
.session-card.current { border-color: rgba(91, 140, 255, .6); box-shadow: 0 0 0 1px rgba(91, 140, 255, .25); }
|
|
124
|
+
.sc-title {
|
|
125
|
+
font-weight: 600; font-size: 15px; white-space: nowrap; overflow: hidden;
|
|
126
|
+
text-overflow: ellipsis; padding-right: 44px;
|
|
127
|
+
}
|
|
128
|
+
.sc-meta { display: flex; gap: 8px; align-items: center; margin-top: 4px; font-size: 12px; color: var(--muted); flex-wrap: wrap; }
|
|
129
|
+
.sc-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); display: inline-block; }
|
|
130
|
+
.sc-dot.running { background: var(--orange); box-shadow: 0 0 8px rgba(255, 158, 100, .9); animation: pulse 1.6s infinite; }
|
|
131
|
+
.sc-dot.pending { background: var(--purple); box-shadow: 0 0 8px rgba(180, 140, 255, .9); }
|
|
132
|
+
@keyframes pulse { 50% { opacity: .45; } }
|
|
133
|
+
.sc-badge {
|
|
134
|
+
font-size: 11px; padding: 1px 7px; border-radius: 999px;
|
|
135
|
+
background: rgba(180, 140, 255, .13); color: var(--purple); border: 1px solid rgba(180, 140, 255, .3);
|
|
136
|
+
}
|
|
137
|
+
.sc-badge.goal-active { background: rgba(125, 207, 255, .12); color: var(--cyan); border-color: rgba(125, 207, 255, .35); }
|
|
138
|
+
.sc-arrow { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); color: var(--muted); }
|
|
139
|
+
.empty { text-align: center; color: var(--muted); padding: 34px 0; }
|
|
140
|
+
|
|
141
|
+
/* ---------- 会话详情 ---------- */
|
|
142
|
+
body.in-session { overflow: hidden; height: 100vh; height: 100dvh; }
|
|
143
|
+
body.in-session .topbar { display: none; }
|
|
144
|
+
body.in-session .main {
|
|
145
|
+
height: 100%;
|
|
146
|
+
display: flex;
|
|
147
|
+
flex-direction: column;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
padding: 12px 12px 76px;
|
|
150
|
+
}
|
|
151
|
+
body.in-session .view {
|
|
152
|
+
flex: 1;
|
|
153
|
+
min-height: 0;
|
|
154
|
+
display: flex;
|
|
155
|
+
flex-direction: column;
|
|
156
|
+
}
|
|
157
|
+
.session-head {
|
|
158
|
+
display: flex; align-items: center; gap: 8px;
|
|
159
|
+
flex-shrink: 0;
|
|
160
|
+
padding: calc(var(--safe-top) + 8px) 12px 8px;
|
|
161
|
+
margin: -12px -12px 6px;
|
|
162
|
+
background: rgba(11, 14, 26, .94);
|
|
163
|
+
backdrop-filter: blur(12px);
|
|
164
|
+
border-bottom: 1px solid var(--line);
|
|
165
|
+
}
|
|
166
|
+
.session-head .session-title { flex-shrink: 1; }
|
|
167
|
+
.session-head-meta { flex: 1; min-width: 0; }
|
|
168
|
+
.session-title {
|
|
169
|
+
font-size: 16px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
170
|
+
}
|
|
171
|
+
.session-sub { font-size: 12px; color: var(--muted); margin-top: 1px; }
|
|
172
|
+
.cards {
|
|
173
|
+
display: flex; flex-direction: column; gap: 8px; margin-top: 8px;
|
|
174
|
+
flex-shrink: 0; max-height: 42vh; overflow-y: auto;
|
|
175
|
+
}
|
|
176
|
+
.card {
|
|
177
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
|
178
|
+
padding: 11px 13px;
|
|
179
|
+
}
|
|
180
|
+
.card-title { font-size: 12px; color: var(--muted); font-weight: 700; letter-spacing: .6px; margin-bottom: 6px; }
|
|
181
|
+
.card-row { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; font-size: 13px; }
|
|
182
|
+
.card-row .k { color: var(--muted); }
|
|
183
|
+
.card-row .v { text-align: right; word-break: break-all; }
|
|
184
|
+
.goal-obj { font-size: 13px; line-height: 1.55; color: var(--text); }
|
|
185
|
+
.goal-phase { font-size: 12px; color: var(--cyan); margin-top: 3px; }
|
|
186
|
+
.goal-actions { display: flex; gap: 8px; margin-top: 9px; flex-wrap: wrap; }
|
|
187
|
+
.goal-actions .mini-btn { flex: 1; text-align: center; min-width: 64px; }
|
|
188
|
+
.pill {
|
|
189
|
+
display: inline-block; font-size: 11px; padding: 1px 8px; border-radius: 999px;
|
|
190
|
+
background: rgba(91, 140, 255, .12); color: var(--blue); border: 1px solid rgba(91, 140, 255, .3);
|
|
191
|
+
margin: 1px 3px 1px 0;
|
|
192
|
+
}
|
|
193
|
+
.pill.done { background: rgba(125, 207, 255, .12); color: var(--cyan); border-color: rgba(125, 207, 255, .3); }
|
|
194
|
+
.pill.active { background: rgba(255, 158, 100, .12); color: var(--orange); border-color: rgba(255, 158, 100, .3); }
|
|
195
|
+
|
|
196
|
+
/* ---------- 历史 ---------- */
|
|
197
|
+
.history-wrap {
|
|
198
|
+
flex: 1; min-height: 0;
|
|
199
|
+
position: relative;
|
|
200
|
+
display: flex;
|
|
201
|
+
}
|
|
202
|
+
.history {
|
|
203
|
+
flex: 1; min-height: 0;
|
|
204
|
+
overflow-y: auto; -webkit-overflow-scrolling: touch;
|
|
205
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
206
|
+
padding-right: 16px;
|
|
207
|
+
scrollbar-width: none;
|
|
208
|
+
}
|
|
209
|
+
.history::-webkit-scrollbar { display: none; }
|
|
210
|
+
.history-more { text-align: center; margin: 4px 0; }
|
|
211
|
+
|
|
212
|
+
/* 右侧导航条: 拇指 + 用户发言节点 */
|
|
213
|
+
.history-rail {
|
|
214
|
+
position: absolute; right: 0; top: 0; bottom: 0; width: 18px;
|
|
215
|
+
z-index: 5; touch-action: none;
|
|
216
|
+
}
|
|
217
|
+
.rail-track {
|
|
218
|
+
position: absolute; right: 8px; top: 4px; bottom: 4px; width: 4px;
|
|
219
|
+
border-radius: 2px; background: var(--line);
|
|
220
|
+
}
|
|
221
|
+
.rail-thumb {
|
|
222
|
+
position: absolute; right: 6px; width: 8px; min-height: 32px;
|
|
223
|
+
border-radius: 4px; background: var(--blue); opacity: .85;
|
|
224
|
+
}
|
|
225
|
+
.rail-nodes { position: absolute; inset: 0; }
|
|
226
|
+
.rail-node {
|
|
227
|
+
position: absolute; right: 7px; width: 6px; height: 6px;
|
|
228
|
+
border-radius: 50%; background: var(--orange); transform: translateY(-3px);
|
|
229
|
+
box-shadow: 0 0 4px rgba(255, 158, 100, .8);
|
|
230
|
+
}
|
|
231
|
+
.rail-node.active { background: #fff; width: 8px; height: 8px; right: 6px; }
|
|
232
|
+
.msg { max-width: 94%; border-radius: var(--radius); padding: 10px 12px; word-break: break-word; }
|
|
233
|
+
.msg.user { align-self: flex-end; background: var(--blue); color: #fff; }
|
|
234
|
+
.msg.assistant { align-self: flex-start; background: var(--panel); border: 1px solid var(--line); }
|
|
235
|
+
.msg .role { font-size: 11px; opacity: .65; margin-bottom: 3px; }
|
|
236
|
+
.msg pre {
|
|
237
|
+
background: rgba(0,0,0,.28); border-radius: 8px; padding: 8px 10px; overflow-x: auto;
|
|
238
|
+
font-size: 12px; max-height: 220px; overflow-y: auto;
|
|
239
|
+
}
|
|
240
|
+
.msg img { max-width: 100%; border-radius: 8px; }
|
|
241
|
+
.msg p { margin: 4px 0; }
|
|
242
|
+
.msg p:first-child { margin-top: 0; } .msg p:last-child { margin-bottom: 0; }
|
|
243
|
+
.msg ul, .msg ol { margin: 4px 0; padding-left: 20px; }
|
|
244
|
+
.msg code { font-family: ui-monospace, monospace; font-size: .9em; background: rgba(91,140,255,.12); padding: 0 4px; border-radius: 4px; }
|
|
245
|
+
|
|
246
|
+
.event {
|
|
247
|
+
align-self: center; font-size: 11px; color: var(--muted);
|
|
248
|
+
background: var(--panel); border: 1px dashed var(--line);
|
|
249
|
+
padding: 5px 12px; border-radius: 999px; max-width: 92%;
|
|
250
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
251
|
+
}
|
|
252
|
+
.tool {
|
|
253
|
+
align-self: flex-start; max-width: 96%; background: var(--panel);
|
|
254
|
+
border: 1px solid var(--line); border-left: 3px solid var(--purple);
|
|
255
|
+
border-radius: 10px; padding: 8px 11px; font-size: 13px;
|
|
256
|
+
}
|
|
257
|
+
.tool summary { cursor: pointer; color: var(--purple); font-weight: 600; }
|
|
258
|
+
.tool-meta-inline { font-size: 11px; color: var(--muted); font-weight: 400; margin-left: 6px; }
|
|
259
|
+
.tool pre { margin: 6px 0 0; font-size: 11.5px; background: rgba(0,0,0,.28); border-radius: 8px; padding: 8px; overflow-x: auto; max-height: 180px; overflow-y: auto; }
|
|
260
|
+
.tool .tool-meta { font-size: 11px; color: var(--muted); margin-top: 4px; }
|
|
261
|
+
.tool-text {
|
|
262
|
+
white-space: pre-wrap; word-break: break-word;
|
|
263
|
+
font-size: 12.5px; line-height: 1.6;
|
|
264
|
+
background: rgba(0,0,0,.28); border-radius: 8px;
|
|
265
|
+
padding: 8px 10px; margin-top: 6px;
|
|
266
|
+
max-height: 320px; overflow-y: auto;
|
|
267
|
+
}
|
|
268
|
+
.tool.result { border-left-color: var(--cyan); }
|
|
269
|
+
.tool.result summary { color: var(--cyan); }
|
|
270
|
+
.tool.error { border-left-color: var(--orange); }
|
|
271
|
+
.tool.error summary { color: var(--orange); }
|
|
272
|
+
|
|
273
|
+
/* ---------- composer ---------- */
|
|
274
|
+
.composer {
|
|
275
|
+
position: fixed; left: 0; right: 0; bottom: calc(58px + var(--safe-b)); z-index: 20;
|
|
276
|
+
display: flex; gap: 8px; align-items: flex-end;
|
|
277
|
+
padding: 8px 12px calc(8px + var(--safe-b));
|
|
278
|
+
background: rgba(11, 14, 26, .92); backdrop-filter: blur(10px);
|
|
279
|
+
border-top: 1px solid var(--line);
|
|
280
|
+
max-width: 720px; margin: 0 auto;
|
|
281
|
+
}
|
|
282
|
+
.composer textarea {
|
|
283
|
+
flex: 1; resize: none; background: var(--panel); color: var(--text);
|
|
284
|
+
border: 1px solid var(--line); border-radius: 16px;
|
|
285
|
+
padding: 10px 14px; font: inherit; font-size: 15px; line-height: 1.4;
|
|
286
|
+
max-height: 120px; outline: none;
|
|
287
|
+
}
|
|
288
|
+
.composer textarea:focus { border-color: rgba(91, 140, 255, .6); }
|
|
289
|
+
.send-btn {
|
|
290
|
+
flex-shrink: 0; width: 46px; height: 42px; border-radius: 14px;
|
|
291
|
+
background: var(--blue); color: #fff; font-weight: 700; font-size: 14px;
|
|
292
|
+
}
|
|
293
|
+
.send-btn:disabled { opacity: .45; }
|
|
294
|
+
body.in-session .main { padding-bottom: 84px; }
|
|
295
|
+
|
|
296
|
+
/* ---------- 待办 ---------- */
|
|
297
|
+
.pending-list, .jobs-list { display: flex; flex-direction: column; gap: 8px; }
|
|
298
|
+
.pending-card, .job-card {
|
|
299
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
|
300
|
+
padding: 11px 13px;
|
|
301
|
+
}
|
|
302
|
+
.pending-card.approval { border-left: 3px solid var(--orange); }
|
|
303
|
+
.pending-card.question { border-left: 3px solid var(--purple); }
|
|
304
|
+
.pc-title { font-weight: 600; font-size: 14px; }
|
|
305
|
+
.pc-desc { font-size: 12.5px; color: var(--muted); margin-top: 3px; word-break: break-all; }
|
|
306
|
+
.pc-session { font-size: 11px; color: var(--blue); margin-top: 5px; }
|
|
307
|
+
.job-card .job-name { font-weight: 600; font-size: 14px; }
|
|
308
|
+
.job-state { font-size: 12px; color: var(--muted); margin-top: 3px; }
|
|
309
|
+
|
|
310
|
+
/* ---------- 设置 ---------- */
|
|
311
|
+
.settings-group {
|
|
312
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
|
|
313
|
+
margin-bottom: 10px; overflow: hidden;
|
|
314
|
+
}
|
|
315
|
+
.setting-row {
|
|
316
|
+
display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
|
317
|
+
padding: 13px 14px;
|
|
318
|
+
}
|
|
319
|
+
.setting-row + .setting-row { border-top: 1px solid var(--line); }
|
|
320
|
+
.setting-name { font-size: 14.5px; font-weight: 600; }
|
|
321
|
+
.setting-desc { font-size: 12px; color: var(--muted); margin-top: 2px; word-break: break-all; }
|
|
322
|
+
.about { text-align: center; color: var(--muted); font-size: 12px; margin-top: 16px; line-height: 1.8; }
|
|
323
|
+
|
|
324
|
+
/* 开关 */
|
|
325
|
+
.switch { position: relative; display: inline-block; width: 46px; height: 27px; flex-shrink: 0; }
|
|
326
|
+
.switch input { opacity: 0; width: 0; height: 0; }
|
|
327
|
+
.slider {
|
|
328
|
+
position: absolute; inset: 0; border-radius: 999px; background: var(--panel-2);
|
|
329
|
+
border: 1px solid var(--line); transition: .2s;
|
|
330
|
+
}
|
|
331
|
+
.slider::before {
|
|
332
|
+
content: ''; position: absolute; width: 19px; height: 19px; border-radius: 50%;
|
|
333
|
+
left: 3px; top: 3px; background: var(--muted); transition: .2s;
|
|
334
|
+
}
|
|
335
|
+
.switch input:checked + .slider { background: rgba(91, 140, 255, .3); border-color: var(--blue); }
|
|
336
|
+
.switch input:checked + .slider::before { transform: translateX(19px); background: var(--blue); }
|
|
337
|
+
|
|
338
|
+
/* ---------- 底部导航 ---------- */
|
|
339
|
+
.bottom-nav {
|
|
340
|
+
position: fixed; left: 0; right: 0; bottom: 0; z-index: 25;
|
|
341
|
+
display: flex; background: rgba(16, 21, 40, .94); backdrop-filter: blur(12px);
|
|
342
|
+
border-top: 1px solid var(--line);
|
|
343
|
+
padding-bottom: var(--safe-b);
|
|
344
|
+
}
|
|
345
|
+
.nav-btn {
|
|
346
|
+
flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
|
|
347
|
+
padding: 8px 0 7px; color: var(--muted); font-size: 11px; position: relative;
|
|
348
|
+
}
|
|
349
|
+
.nav-btn .nav-ico { font-size: 19px; line-height: 1; }
|
|
350
|
+
.nav-btn.active { color: var(--blue); }
|
|
351
|
+
.nav-badge {
|
|
352
|
+
position: absolute; top: 4px; left: calc(50% + 10px);
|
|
353
|
+
background: var(--orange); color: #1a120b; border-radius: 999px;
|
|
354
|
+
font-size: 10px; font-weight: 800; padding: 0 6px; line-height: 16px;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* ---------- 模态 ---------- */
|
|
358
|
+
.modal {
|
|
359
|
+
position: fixed; inset: 0; z-index: 40; display: grid; place-items: center;
|
|
360
|
+
background: rgba(5, 7, 14, .66); backdrop-filter: blur(3px); padding: 18px;
|
|
361
|
+
}
|
|
362
|
+
.modal-card {
|
|
363
|
+
width: 100%; max-width: 460px; max-height: 82vh; overflow-y: auto;
|
|
364
|
+
background: var(--bg-2); border: 1px solid var(--line); border-radius: 18px;
|
|
365
|
+
padding: 16px;
|
|
366
|
+
}
|
|
367
|
+
.modal-title { font-size: 16px; font-weight: 700; margin-bottom: 10px; }
|
|
368
|
+
.modal-body { font-size: 14px; }
|
|
369
|
+
.modal-body .q-item { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 11px 12px; margin-bottom: 10px; }
|
|
370
|
+
.modal-body .q-text { font-weight: 600; margin-bottom: 8px; }
|
|
371
|
+
.modal-body .q-option {
|
|
372
|
+
display: flex; gap: 8px; align-items: flex-start; padding: 7px 6px; border-radius: 8px;
|
|
373
|
+
}
|
|
374
|
+
.modal-body input[type='radio'], .modal-body input[type='checkbox'] { accent-color: var(--blue); margin-top: 3px; }
|
|
375
|
+
.modal-body textarea {
|
|
376
|
+
width: 100%; margin-top: 8px; background: var(--panel); color: var(--text);
|
|
377
|
+
border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; font: inherit; outline: none;
|
|
378
|
+
}
|
|
379
|
+
.modal-actions { display: flex; gap: 9px; margin-top: 14px; }
|
|
380
|
+
.kv { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; padding: 3px 0; }
|
|
381
|
+
.kv .k { color: var(--muted); } .kv .v { word-break: break-all; text-align: right; }
|
|
382
|
+
|
|
383
|
+
/* ---------- toast ---------- */
|
|
384
|
+
.toast {
|
|
385
|
+
position: fixed; top: calc(58px + var(--safe-top)); left: 50%; transform: translateX(-50%);
|
|
386
|
+
z-index: 60; background: var(--panel-2); border: 1px solid var(--line);
|
|
387
|
+
color: var(--text); padding: 9px 16px; border-radius: 999px; font-size: 13px;
|
|
388
|
+
max-width: 88vw; box-shadow: 0 6px 24px rgba(0,0,0,.4);
|
|
389
|
+
}
|
|
390
|
+
.toast.err { border-color: rgba(255, 143, 107, .6); color: var(--danger); }
|
|
391
|
+
.toast.ok { border-color: rgba(125, 207, 255, .6); color: var(--cyan); }
|
|
392
|
+
|
|
393
|
+
@media (min-width: 560px) {
|
|
394
|
+
.stat-strip { grid-template-columns: repeat(3, 1fr); }
|
|
395
|
+
.msg { max-width: 78%; }
|
|
396
|
+
}
|