dsh-mini-remote 0.1.4 → 0.1.5
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/CHANGELOG.md +19 -0
- package/README.en.md +83 -33
- package/README.md +83 -33
- package/lib/build.js +11 -5
- package/lib/page.html +357 -112
- package/package.json +1 -1
package/lib/page.html
CHANGED
|
@@ -3,29 +3,90 @@
|
|
|
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="#0a0f16">
|
|
7
7
|
<meta name="mobile-web-app-capable" content="yes">
|
|
8
8
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
9
9
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
10
|
-
<title
|
|
10
|
+
<title>极简遥控器</title>
|
|
11
11
|
<style>
|
|
12
|
+
/* ---------- 设计令牌 ----------
|
|
13
|
+
规格来自用户 2026-09-27 定的六关键词翻译表,改之前先读这一段:
|
|
14
|
+
· 圆角只有两档:卡片一律 2px,状态点用 999px/50%。**没有中间档**。
|
|
15
|
+
· 阴影只有两档,且都极浅;层次主要靠 --line 这条 1px 细线和间距建立。
|
|
16
|
+
· 强调色分两个角色,加起来**一屏最多两处**:
|
|
17
|
+
--gold 是**当字/点**用的(刻度上"当前这一步");--act 是**当底**用的(主按钮)。
|
|
18
|
+
深色下两个都是暖金 #c9a55c;浅色下 --gold 压深成 #8a6529(白底才读得清),
|
|
19
|
+
--act 换成宣传图的宝蓝 #3b6fc4——用户 2026-09-27 看过对照图后定的:浅色那套
|
|
20
|
+
底色本来就是从宣传图取的,冷底上再压一块饱和暖金,比在深色下更像外来物。
|
|
21
|
+
需要"显眼一点"的地方一律用鲸鱼娘的冰蓝 --ice,别动这两个。
|
|
22
|
+
· --ok/--run/--err 是状态点的语义色,占的是 8px 一个小点,不算强调色。
|
|
23
|
+
· 配色以鲸鱼娘为准心:深海墨蓝打底,她的冰蓝作次级色。
|
|
24
|
+
· 两套主题:这套(默认,深色)和 [data-theme="light"],色调跟宣传图
|
|
25
|
+
(docs/promo.png)统一。**颜色令牌两边必须一一对应**——缺一个,就有元素
|
|
26
|
+
在某个主题下"隐身",而且只在那个主题下才看得出来。守卫在 test/ui.test.mjs。 */
|
|
12
27
|
:root {
|
|
13
|
-
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
--
|
|
18
|
-
--
|
|
19
|
-
--
|
|
20
|
-
--
|
|
21
|
-
--
|
|
22
|
-
--
|
|
23
|
-
--
|
|
28
|
+
color-scheme: dark;
|
|
29
|
+
--bg: #0a0f16;
|
|
30
|
+
--bg-top: #101a27;
|
|
31
|
+
--bg-deep: #070b11;
|
|
32
|
+
--panel: #121a25;
|
|
33
|
+
--panel-2: #18222f;
|
|
34
|
+
--line: #22303f;
|
|
35
|
+
--fg: #e3ebf4;
|
|
36
|
+
--muted: #7b8a9b;
|
|
37
|
+
--dim: #6c7a8b;
|
|
38
|
+
--ice: #a9c8e8;
|
|
39
|
+
--gold: #c9a55c; /* 强调色当**字/点**用:刻度上"当前这一步" */
|
|
40
|
+
--act: #c9a55c; /* 强调色当**底**用:一屏一个的主按钮 */
|
|
41
|
+
--ok: #4fb477;
|
|
42
|
+
--run: #a9c8e8;
|
|
43
|
+
--err: #d4614f;
|
|
44
|
+
--r: 2px;
|
|
45
|
+
--sh-1: 0 1px 2px rgba(0, 0, 0, .28);
|
|
46
|
+
--sh-2: 0 2px 6px rgba(0, 0, 0, .34);
|
|
47
|
+
--glass: rgba(18, 26, 37, .72);
|
|
48
|
+
--tint: rgba(24, 34, 47, .5); /* 队列那块比面板再深一点的底 */
|
|
49
|
+
--pop: rgba(24, 34, 47, .97); /* 浮起来的小面板(指令菜单等) */
|
|
50
|
+
--scrim: rgba(0, 0, 0, .55); /* 弹出层背后压暗的那层;浅色主题里它得轻得多 */
|
|
51
|
+
--on-act: #10161f; /* 实心主按钮上的字:金底配白字读不清 */
|
|
52
|
+
}
|
|
53
|
+
/* 浅色主题:色调跟宣传图(docs/promo.png)统一——近白的冰蓝底、深宝蓝的字与状态色、
|
|
54
|
+
白色卡片、极浅的蓝投影。深色那边的规矩一条不改:圆角两档、层次靠 1px 细线。
|
|
55
|
+
强调色在浅色下分了家:当字/点用的金压深到 #8a6529,当底用的主按钮换成宣传图的宝蓝
|
|
56
|
+
(#3b6fc4 配白字)——用户 2026-09-27 看过对照图后定的。
|
|
57
|
+
切换入口在设置页「外观」;选择存在 localStorage,首屏之前就定好,不会闪一下。 */
|
|
58
|
+
[data-theme="light"] {
|
|
59
|
+
color-scheme: light;
|
|
60
|
+
--bg: #eaf3fc;
|
|
61
|
+
--bg-top: #f7fbff;
|
|
62
|
+
--bg-deep: #dbe9f8;
|
|
63
|
+
--panel: #ffffff;
|
|
64
|
+
--panel-2: #f2f8ff;
|
|
65
|
+
--line: #d3e2f3;
|
|
66
|
+
--fg: #1b2c49;
|
|
67
|
+
--muted: #6b7f9b;
|
|
68
|
+
--dim: #8496ae;
|
|
69
|
+
--ice: #3b6fc4;
|
|
70
|
+
--gold: #8a6529; /* 白底上当字用,得压深才读得清 */
|
|
71
|
+
--act: #3b6fc4; /* 主按钮底:用宣传图那个宝蓝(用户 2026-09-27 裁决) */
|
|
72
|
+
--ok: #2e9a5f;
|
|
73
|
+
--run: #3b6fc4;
|
|
74
|
+
--err: #c0392b;
|
|
75
|
+
--sh-1: 0 1px 2px rgba(28, 60, 110, .07);
|
|
76
|
+
--sh-2: 0 2px 8px rgba(28, 60, 110, .12);
|
|
77
|
+
--glass: rgba(255, 255, 255, .74);
|
|
78
|
+
--tint: rgba(59, 111, 196, .07);
|
|
79
|
+
--pop: rgba(255, 255, 255, .98);
|
|
80
|
+
--scrim: rgba(23, 52, 95, .30);
|
|
81
|
+
--on-act: #ffffff; /* 宝蓝底上的字 */
|
|
24
82
|
}
|
|
25
83
|
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
|
|
26
84
|
html, body {
|
|
27
85
|
margin: 0; height: 100%; overflow: hidden;
|
|
28
|
-
|
|
86
|
+
/* 纵深:顶部略亮、底部更深,做出"空间"而不是一整块平色。
|
|
87
|
+
设计稿参考的是沉浸式暗色流媒体那一套——界面浮在深色基底上,不是被切成几块。 */
|
|
88
|
+
background: linear-gradient(180deg, var(--bg-top) 0%, var(--bg) 55%, var(--bg-deep) 100%);
|
|
89
|
+
color: var(--fg);
|
|
29
90
|
font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
|
30
91
|
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
|
31
92
|
overscroll-behavior: none;
|
|
@@ -33,24 +94,32 @@
|
|
|
33
94
|
body { display: flex; flex-direction: column; }
|
|
34
95
|
|
|
35
96
|
/* ---------- 顶栏 ---------- */
|
|
97
|
+
/* 顶栏和底栏是两块**悬浮毛玻璃**:内容从它们底下淡出,界面像浮着,
|
|
98
|
+
而不是上下两条实心色带把屏幕切成三块。 */
|
|
36
99
|
header {
|
|
37
100
|
flex: 0 0 auto; display: flex; align-items: center; gap: 10px;
|
|
38
101
|
padding: calc(env(safe-area-inset-top) + 10px) 14px 10px;
|
|
39
|
-
background: var(--
|
|
102
|
+
background: var(--glass); border-bottom: 1px solid var(--line);
|
|
103
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
104
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
40
105
|
}
|
|
41
106
|
.brand { font-weight: 600; letter-spacing: .3px; }
|
|
42
107
|
.dot {
|
|
43
108
|
width: 8px; height: 8px; border-radius: 50%;
|
|
44
|
-
background: var(--muted); flex: 0 0 auto;
|
|
109
|
+
background: var(--muted); flex: 0 0 auto;
|
|
110
|
+
/* 状态变化是**瞬时**的:数据在变,界面不表演。
|
|
111
|
+
这里原来挂着一圈 1.2s 的呼吸闪动,2026-09-27 按规格删掉了——
|
|
112
|
+
"正在思考"的脉动圆点是那几年的视觉套话;而"它在动"这件事,下面那块正在执行区
|
|
113
|
+
里她说的那句话和秒数已经说得更准,也更安静。160ms 是本页唯一保留的过渡节奏。 */
|
|
114
|
+
transition: background .16s;
|
|
45
115
|
}
|
|
46
116
|
.dot.ok { background: var(--ok); }
|
|
47
|
-
.dot.run { background: var(--
|
|
117
|
+
.dot.run { background: var(--run); }
|
|
48
118
|
.dot.err { background: var(--err); }
|
|
49
|
-
@keyframes pulse { 50% { opacity: .25; } }
|
|
50
119
|
.status { color: var(--muted); font-size: 13px; flex: 1 1 auto;
|
|
51
120
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
52
121
|
.icon-btn {
|
|
53
|
-
flex: 0 0 auto; width: 36px; height: 36px; border-radius:
|
|
122
|
+
flex: 0 0 auto; width: 36px; height: 36px; border-radius: var(--r);
|
|
54
123
|
border: 1px solid var(--line); background: var(--panel-2); color: var(--fg);
|
|
55
124
|
font-size: 16px; display: grid; place-items: center; cursor: pointer;
|
|
56
125
|
}
|
|
@@ -64,11 +133,11 @@
|
|
|
64
133
|
white-space: pre-wrap; word-break: break-word;
|
|
65
134
|
font-size: 16px; line-height: 1.75;
|
|
66
135
|
}
|
|
67
|
-
#reply a { color: var(--
|
|
136
|
+
#reply a { color: var(--ice); }
|
|
68
137
|
.placeholder { color: var(--muted); font-size: 15px; text-align: center; line-height: 1.9; }
|
|
69
138
|
.placeholder kbd {
|
|
70
139
|
background: var(--panel-2); border: 1px solid var(--line);
|
|
71
|
-
border-radius:
|
|
140
|
+
border-radius: var(--r); padding: 1px 6px; font-size: 13px; font-family: inherit;
|
|
72
141
|
}
|
|
73
142
|
|
|
74
143
|
/* ---------- 聊天模式 ---------- */
|
|
@@ -79,7 +148,7 @@
|
|
|
79
148
|
两种气泡都要,只改一边的话,短回复那边还是会露出大方块,看着像坏了。 */
|
|
80
149
|
.bubble {
|
|
81
150
|
width: fit-content;
|
|
82
|
-
max-width: 86%; padding: 10px 13px; border-radius: var(--
|
|
151
|
+
max-width: 86%; padding: 10px 13px; border-radius: var(--r);
|
|
83
152
|
/* 18px,和 .said 的下边距一致。原来是 10px,用户 2026-09-22 实机提「指令气泡和
|
|
84
153
|
回答正文第一行之间贴得太紧」——10px 是「同一条消息内部」的距离,
|
|
85
154
|
而这里跨的是「我说的话」和「它答的话」,是更大的一个断点,该给更多。 */
|
|
@@ -88,12 +157,12 @@
|
|
|
88
157
|
}
|
|
89
158
|
.bubble.user { margin-left: auto; background: var(--panel-2); border: 1px solid var(--line); }
|
|
90
159
|
.bubble.assistant { margin-right: auto; background: var(--panel); border: 1px solid var(--line); }
|
|
91
|
-
.bubble a { color: var(--
|
|
160
|
+
.bubble a { color: var(--ice); }
|
|
92
161
|
.bubble .meta { display: block; margin-top: 6px; font-size: 11px; color: var(--muted); }
|
|
93
162
|
/* 「已停止」标签:被按停的那一轮,手机上收到的只是**已经吐出来的那半句**。
|
|
94
163
|
不标出来的话,它看着就像模型答崩了。 */
|
|
95
164
|
.stopped {
|
|
96
|
-
display: inline-block; padding: 1px 7px; border-radius:
|
|
165
|
+
display: inline-block; padding: 1px 7px; border-radius: var(--r); font-size: 11px;
|
|
97
166
|
color: var(--muted); border: 1px solid var(--line); vertical-align: middle;
|
|
98
167
|
}
|
|
99
168
|
.reply-bar .stopped { margin-right: auto; }
|
|
@@ -101,6 +170,12 @@
|
|
|
101
170
|
/* 外层是 pre-wrap(用户消息和旧内容靠它),markdown 输出的是真块级元素,
|
|
102
171
|
所以要在这里把 pre-wrap 收掉,否则段落之间会多出一堆空行。 */
|
|
103
172
|
.md { white-space: normal; }
|
|
173
|
+
/* 回复里的图。地址有两种写法,见下面 mdInline() 里那段注释。
|
|
174
|
+
宽度只封顶不写死:窄屏上占满可用宽度、按比例缩,圆角沿用全站那 2 像素。 */
|
|
175
|
+
.md-img {
|
|
176
|
+
display: block; max-width: 100%; height: auto; margin: 10px 0;
|
|
177
|
+
border-radius: var(--r); border: 1px solid var(--line); background: var(--panel-2);
|
|
178
|
+
}
|
|
104
179
|
.md > :first-child { margin-top: 0; }
|
|
105
180
|
.md > :last-child { margin-bottom: 0; }
|
|
106
181
|
.md p { margin: 0 0 .7em; }
|
|
@@ -113,7 +188,7 @@
|
|
|
113
188
|
.md h4, .md h5, .md h6 { font-size: 1em; }
|
|
114
189
|
.md ul, .md ol { margin: 0 0 .7em; padding-left: 1.4em; }
|
|
115
190
|
.md li { margin: .18em 0; }
|
|
116
|
-
.md a { color: var(--
|
|
191
|
+
.md a { color: var(--ice); word-break: break-all; }
|
|
117
192
|
.md strong { font-weight: 650; }
|
|
118
193
|
.md hr { border: none; border-top: 1px solid var(--line); margin: 1em 0; }
|
|
119
194
|
.md blockquote {
|
|
@@ -121,12 +196,12 @@
|
|
|
121
196
|
border-left: 3px solid var(--line); color: var(--muted);
|
|
122
197
|
}
|
|
123
198
|
.md code {
|
|
124
|
-
background: var(--panel-2); border: 1px solid var(--line); border-radius:
|
|
199
|
+
background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r);
|
|
125
200
|
padding: .1em .35em; font-size: .88em;
|
|
126
201
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
127
202
|
}
|
|
128
203
|
.md .code {
|
|
129
|
-
margin: 0 0 .7em; border: 1px solid var(--line); border-radius:
|
|
204
|
+
margin: 0 0 .7em; border: 1px solid var(--line); border-radius: var(--r);
|
|
130
205
|
background: var(--panel-2); overflow: hidden;
|
|
131
206
|
}
|
|
132
207
|
.md .code-head {
|
|
@@ -150,7 +225,7 @@
|
|
|
150
225
|
三个地方共用:单帧模式的整篇、聊天模式的气泡、代码块。 */
|
|
151
226
|
.copy {
|
|
152
227
|
flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
|
|
153
|
-
width: 28px; height: 28px; padding: 0; border-radius:
|
|
228
|
+
width: 28px; height: 28px; padding: 0; border-radius: var(--r); cursor: pointer;
|
|
154
229
|
border: 1px solid var(--line); background: var(--panel-2); color: var(--muted);
|
|
155
230
|
}
|
|
156
231
|
.copy svg {
|
|
@@ -158,7 +233,7 @@
|
|
|
158
233
|
stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
|
|
159
234
|
}
|
|
160
235
|
.copy:active { transform: scale(.95); }
|
|
161
|
-
.copy.done { color: var(--
|
|
236
|
+
.copy.done { color: var(--ice); border-color: var(--ice); }
|
|
162
237
|
.bubble .meta .copy { margin-left: 8px; vertical-align: middle; }
|
|
163
238
|
/* 上面那条只放「已停止」标签——它是给正文打的预防针,得在正文之前出现。
|
|
164
239
|
复制按钮挪到正文下面去了(.reply-foot)。 */
|
|
@@ -177,7 +252,7 @@
|
|
|
177
252
|
display: flex; align-items: baseline; gap: 8px;
|
|
178
253
|
width: fit-content; max-width: 100%;
|
|
179
254
|
margin: 0 0 14px; padding: 4px 10px 4px 9px;
|
|
180
|
-
border-left: 2px solid var(--line); border-radius: 0
|
|
255
|
+
border-left: 2px solid var(--line); border-radius: 0 var(--r) var(--r) 0;
|
|
181
256
|
background: var(--panel-2); font-size: 13px; line-height: 1.5;
|
|
182
257
|
}
|
|
183
258
|
/* 名字加参数排一行,太长就省略——它是「做了哪件事」的标签,不是正文。 */
|
|
@@ -202,7 +277,7 @@
|
|
|
202
277
|
.live .md > *:last-child::after {
|
|
203
278
|
content: ''; display: inline-block; width: 2px; height: 1em;
|
|
204
279
|
margin-left: 2px; vertical-align: -2px;
|
|
205
|
-
background: var(--
|
|
280
|
+
background: var(--ice);
|
|
206
281
|
animation: caret 1s steps(2, start) infinite;
|
|
207
282
|
}
|
|
208
283
|
@keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
|
|
@@ -239,10 +314,9 @@
|
|
|
239
314
|
.work-stage {
|
|
240
315
|
position: relative; flex: 0 0 auto;
|
|
241
316
|
width: 122px; height: 106px;
|
|
242
|
-
/*
|
|
243
|
-
|
|
317
|
+
/* 这里原来还叠着一层 2.4s 的上下浮动(`workBob`),2026-09-27 删掉:
|
|
318
|
+
她的翻帧本身就是"活着"的证据,再叠一层漂浮就变成界面在表演了。 */
|
|
244
319
|
}
|
|
245
|
-
@keyframes workBob { 50% { transform: translateY(-3px); } }
|
|
246
320
|
.pose {
|
|
247
321
|
position: absolute; inset: 0;
|
|
248
322
|
background-repeat: no-repeat;
|
|
@@ -278,7 +352,7 @@
|
|
|
278
352
|
max-width: calc(100% - 128px);
|
|
279
353
|
align-self: flex-start; margin-top: 6px;
|
|
280
354
|
background: var(--panel-2); border: 1px solid var(--line);
|
|
281
|
-
border-radius:
|
|
355
|
+
border-radius: var(--r); padding: 9px 12px;
|
|
282
356
|
font-size: 14.5px; line-height: 1.5; color: var(--fg);
|
|
283
357
|
max-height: 50vh; overflow-y: auto;
|
|
284
358
|
/* 长英文串、URL 不认换行,会把气泡顶宽。中文本来就能任意断行,这条是给它们兜的。 */
|
|
@@ -299,28 +373,40 @@
|
|
|
299
373
|
/* 气泡里的话走和回答区同一套行内渲染(`mdInline`):`**加粗**`、`` `代码` ``、链接会变成样式。
|
|
300
374
|
代码的底色特意不用 --panel-2——那是气泡自己的底色,套上去等于看不见。 */
|
|
301
375
|
.work-bubble strong { font-weight: 650; }
|
|
302
|
-
.work-bubble a { color: var(--
|
|
376
|
+
.work-bubble a { color: var(--ice); word-break: break-all; }
|
|
303
377
|
.work-bubble code {
|
|
304
|
-
background: rgba(127, 127, 127, .18); border: 1px solid var(--line); border-radius:
|
|
378
|
+
background: rgba(127, 127, 127, .18); border: 1px solid var(--line); border-radius: var(--r);
|
|
305
379
|
padding: .1em .35em; font-size: .88em;
|
|
306
380
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
307
381
|
}
|
|
308
382
|
|
|
309
|
-
/*
|
|
383
|
+
/* 进度条是**不确定进度**,不是百分比。
|
|
310
384
|
插件按设计只收「指令 + 最终回复」,拿不到 Agent 此刻跑到哪一步,
|
|
311
|
-
所以画一个填到 80% 的假进度条等于撒谎。它只表达「在跑」,不表达「跑到哪了」。
|
|
385
|
+
所以画一个填到 80% 的假进度条等于撒谎。它只表达「在跑」,不表达「跑到哪了」。
|
|
386
|
+
|
|
387
|
+
这一段前后改过三次,方向来回,写清楚免得再兜圈子:
|
|
388
|
+
① 最初是一条来回扫的流光(`workSweep`),按 UI 规格删掉——流光属于"看起来在动"
|
|
389
|
+
的廉价套话;
|
|
390
|
+
② 删完剩一根**定在 38% 的静态标记**。结果更糟:用户实机一看就问「底部的进度条
|
|
391
|
+
好像不会动」,而一根停在三成八的线,比一个会动的它**更**像在谎报百分比;
|
|
392
|
+
③ 现在:宽度写死 38% 永不改变,动的是**位置**——十六格一轮、每格 160ms,
|
|
393
|
+
也就是全页那一个节奏。推进式(steps)而不是匀速流淌。
|
|
394
|
+
它仍然不知道跑了多少;它只是不再假装停住。 */
|
|
312
395
|
.work-progress {
|
|
313
|
-
margin-top: 10px; height:
|
|
314
|
-
background: var(--
|
|
396
|
+
margin-top: 10px; height: 1px;
|
|
397
|
+
background: var(--line); overflow: hidden;
|
|
315
398
|
}
|
|
316
399
|
.work-progress i {
|
|
317
|
-
display: block; width: 38%; height: 100%;
|
|
318
|
-
background:
|
|
319
|
-
animation:
|
|
400
|
+
display: block; width: 38%; height: 100%;
|
|
401
|
+
background: var(--ice);
|
|
402
|
+
animation: barStep 2.56s steps(16, end) infinite;
|
|
320
403
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
404
|
+
/* 从左外侧进来、从右外侧出去。38% 宽的块想走完一整条轨道,位移得是自身宽度的
|
|
405
|
+
263%(100 ÷ 38 ≈ 2.63)。用 steps 而不是匀速:一格一格地推进,
|
|
406
|
+
跟上面那把刻度尺是同一种秩序感。 */
|
|
407
|
+
@keyframes barStep {
|
|
408
|
+
from { transform: translateX(-100%); }
|
|
409
|
+
to { transform: translateX(263%); }
|
|
324
410
|
}
|
|
325
411
|
/* 秒数在左、停止按钮在右。秒数原来是自己一行右对齐,现在跟按钮同一行。 */
|
|
326
412
|
.work-foot {
|
|
@@ -334,7 +420,7 @@
|
|
|
334
420
|
按下去之后自己禁用并改文案——cancel() 只是递请求,真正停下要等状态翻,
|
|
335
421
|
这中间必须让用户看见「已经按到了」,否则会连按好几下。 */
|
|
336
422
|
.stop {
|
|
337
|
-
padding: 5px 14px; border-radius:
|
|
423
|
+
padding: 5px 14px; border-radius: var(--r); font-size: 13px;
|
|
338
424
|
border: 1px solid var(--line); background: transparent; color: var(--fg);
|
|
339
425
|
transition: opacity .15s;
|
|
340
426
|
}
|
|
@@ -343,11 +429,44 @@
|
|
|
343
429
|
/* 排队中的指令。跑着任务时接着发的那几条排在这儿,等这一轮跑完再跑。
|
|
344
430
|
单帧模式下你发出去的那句话在别处一个字都看不见(那一模式只显示回复),
|
|
345
431
|
所以这块是唯一的反馈,不能省。 */
|
|
432
|
+
/* ---------- 工序刻度尺 ----------
|
|
433
|
+
**它代表的是"队列",不是 Agent 的工序。** 插件按设计只收「指令 + 最终回复」,
|
|
434
|
+
根本看不到 Agent 此刻跑到哪一步(见上面进度条那一段)。所以刻度上每个点都对应
|
|
435
|
+
一条真实存在的指令:第一个点是**正在跑的那条**(暖金),后面是排着队的(空心)。
|
|
436
|
+
设计稿里画的是一条理想中的工序进度尺;落到真实实现,只有队列是插件真知道的事,
|
|
437
|
+
就按队列画——界面上不出现编出来的数据。 */
|
|
346
438
|
.queue {
|
|
347
|
-
margin-top: 12px; padding:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
439
|
+
margin-top: 12px; padding: 12px;
|
|
440
|
+
border: 1px solid var(--line); border-radius: var(--r);
|
|
441
|
+
background: var(--tint);
|
|
442
|
+
}
|
|
443
|
+
.queue .q-head { font-size: 11.5px; color: var(--muted); margin-bottom: 10px; }
|
|
444
|
+
.queue .q-scale {
|
|
445
|
+
position: relative; display: flex; align-items: center; height: 24px; margin: 2px 0 10px;
|
|
446
|
+
}
|
|
447
|
+
/* 刻度之间的那条细线:垫在点底下,两端各留 3px,不顶到边。 */
|
|
448
|
+
.queue .q-scale::before {
|
|
449
|
+
content: ''; position: absolute; left: 3px; right: 3px; top: 6px;
|
|
450
|
+
height: 1px; background: var(--line);
|
|
451
|
+
}
|
|
452
|
+
.queue .q-node {
|
|
453
|
+
position: relative; flex: 1 1 0; display: flex; flex-direction: column;
|
|
454
|
+
align-items: center; gap: 5px;
|
|
455
|
+
}
|
|
456
|
+
.queue .q-node i {
|
|
457
|
+
display: block; width: 7px; height: 7px; border-radius: 50%;
|
|
458
|
+
box-sizing: content-box; border: 1px solid var(--line); background: var(--bg);
|
|
459
|
+
/* 全页唯一允许的动效:节点由"待"变"过"时 160ms 颜色过渡。 */
|
|
460
|
+
transition: background .16s ease, border-color .16s ease;
|
|
461
|
+
}
|
|
462
|
+
/* 刻度上"当前这一步"是**当字用**的那个强调色(--gold):浅色主题底下它要压深,
|
|
463
|
+
所以这里是 --gold 而不是 --act——--act 是"当底用"的,浅色下已经换成宝蓝了。 */
|
|
464
|
+
.queue .q-node.cur i { background: var(--gold); border-color: var(--gold); }
|
|
465
|
+
.queue .q-node b {
|
|
466
|
+
font-weight: 400; font-size: 10.5px; line-height: 1;
|
|
467
|
+
color: var(--muted); font-variant-numeric: tabular-nums;
|
|
468
|
+
}
|
|
469
|
+
.queue .q-node.cur b { color: var(--gold); }
|
|
351
470
|
.queue .q-row {
|
|
352
471
|
display: flex; align-items: center; gap: 8px; padding: 3px 0;
|
|
353
472
|
font-size: 13.5px; line-height: 1.45;
|
|
@@ -360,41 +479,51 @@
|
|
|
360
479
|
}
|
|
361
480
|
.queue .q-drop {
|
|
362
481
|
flex: 0 0 auto; width: 24px; height: 24px; padding: 0; line-height: 1;
|
|
363
|
-
border-radius:
|
|
482
|
+
border-radius: var(--r); font-size: 12px;
|
|
364
483
|
border: 1px solid var(--line); background: transparent; color: var(--muted);
|
|
365
484
|
}
|
|
485
|
+
.queue .q-drop svg {
|
|
486
|
+
width: 12px; height: 12px; fill: none; stroke: currentColor;
|
|
487
|
+
stroke-width: 1.6; stroke-linecap: round;
|
|
488
|
+
}
|
|
366
489
|
|
|
367
490
|
/* 系统里设了「减少动态效果」的人:不浮动、不翻帧、不轮播、进度条常亮。
|
|
368
491
|
秒数照常走——那是信息,不是装饰。 */
|
|
369
492
|
@media (prefers-reduced-motion: reduce) {
|
|
370
493
|
.work-stage { animation: none; }
|
|
371
494
|
.pose { animation: none; transition: none; }
|
|
372
|
-
.work-progress i {
|
|
495
|
+
.work-progress i { width: 100%; opacity: .45; animation: none; }
|
|
496
|
+
.queue .q-node i { transition: none; }
|
|
497
|
+
.dot { transition: none; }
|
|
373
498
|
}
|
|
374
499
|
|
|
375
500
|
/* ---------- 底栏 ---------- */
|
|
376
501
|
footer {
|
|
377
502
|
flex: 0 0 auto; display: flex; align-items: flex-end; gap: 8px;
|
|
378
503
|
padding: 10px 12px calc(env(safe-area-inset-bottom) + 10px);
|
|
379
|
-
background: var(--
|
|
504
|
+
background: var(--glass); border-top: 1px solid var(--line);
|
|
505
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
506
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
380
507
|
}
|
|
381
508
|
#input {
|
|
382
509
|
flex: 1 1 auto; resize: none; min-height: 42px; max-height: 140px;
|
|
383
|
-
padding: 10px 12px; border-radius:
|
|
510
|
+
padding: 10px 12px; border-radius: var(--r); border: 1px solid var(--line);
|
|
384
511
|
background: var(--panel-2); color: var(--fg); font: inherit; font-size: 16px;
|
|
385
512
|
line-height: 1.5; outline: none;
|
|
386
513
|
}
|
|
387
|
-
#input:focus { border-color: var(--
|
|
514
|
+
#input:focus { border-color: var(--ice); }
|
|
515
|
+
/* 发送键是这一屏**唯一的暖金**(另一处是刻度上"正在跑的那一步")。
|
|
516
|
+
金色底配白字读不清,所以字用近黑的 --on-act。(浅色下 --act 是宝蓝、--on-act 是白字。) */
|
|
388
517
|
.send {
|
|
389
|
-
flex: 0 0 auto; height: 42px; padding: 0 16px; border-radius:
|
|
390
|
-
border: none; background: var(--
|
|
518
|
+
flex: 0 0 auto; height: 42px; padding: 0 16px; border-radius: var(--r);
|
|
519
|
+
border: none; background: var(--act); color: var(--on-act);
|
|
391
520
|
font-size: 15px; font-weight: 600; cursor: pointer;
|
|
392
521
|
}
|
|
393
522
|
.send:disabled { opacity: .4; }
|
|
394
523
|
|
|
395
524
|
/* ---------- 上传附件 ---------- */
|
|
396
525
|
.attach {
|
|
397
|
-
flex: 0 0 auto; width: 42px; height: 42px; padding: 0; border-radius:
|
|
526
|
+
flex: 0 0 auto; width: 42px; height: 42px; padding: 0; border-radius: var(--r);
|
|
398
527
|
border: 1px solid var(--line); background: var(--panel-2); color: var(--muted);
|
|
399
528
|
display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
|
|
400
529
|
}
|
|
@@ -407,12 +536,14 @@
|
|
|
407
536
|
/* 附件小条:排在输入框上面,让你发之前看得见自己带了什么。 */
|
|
408
537
|
.attach-bar {
|
|
409
538
|
flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 6px;
|
|
410
|
-
padding: 8px 12px 0; background: var(--
|
|
539
|
+
padding: 8px 12px 0; background: var(--glass); border-top: 1px solid var(--line);
|
|
540
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
541
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
411
542
|
}
|
|
412
543
|
.attach-bar[hidden] { display: none; }
|
|
413
544
|
.chip {
|
|
414
545
|
display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
|
|
415
|
-
padding: 5px 6px 5px 10px; border-radius:
|
|
546
|
+
padding: 5px 6px 5px 10px; border-radius: var(--r);
|
|
416
547
|
border: 1px solid var(--line); background: var(--panel-2);
|
|
417
548
|
font-size: 12.5px; color: var(--fg);
|
|
418
549
|
}
|
|
@@ -431,17 +562,19 @@
|
|
|
431
562
|
.cmd-menu {
|
|
432
563
|
flex: 0 0 auto; max-height: 42vh; overflow-y: auto;
|
|
433
564
|
-webkit-overflow-scrolling: touch;
|
|
434
|
-
padding: 6px 8px; background: var(--
|
|
565
|
+
padding: 6px 8px; background: var(--glass); border-top: 1px solid var(--line);
|
|
566
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
567
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
435
568
|
}
|
|
436
569
|
.cmd-menu[hidden] { display: none; }
|
|
437
570
|
.cmd-menu .cmd-row {
|
|
438
571
|
display: flex; align-items: baseline; gap: 10px; width: 100%;
|
|
439
|
-
padding: 9px 8px; border: none; border-radius:
|
|
572
|
+
padding: 9px 8px; border: none; border-radius: var(--r); background: none;
|
|
440
573
|
color: var(--fg); font: inherit; font-size: 14.5px; text-align: left; cursor: pointer;
|
|
441
574
|
}
|
|
442
575
|
.cmd-menu .cmd-row:active { background: var(--panel-2); }
|
|
443
576
|
.cmd-menu .cmd-name {
|
|
444
|
-
flex: 0 0 auto; color: var(--
|
|
577
|
+
flex: 0 0 auto; color: var(--ice);
|
|
445
578
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
446
579
|
}
|
|
447
580
|
/* 说明收成一行:这一屏是「扫一眼挑一个」,不是读文档的地方。 */
|
|
@@ -456,18 +589,20 @@
|
|
|
456
589
|
/* ---------- 左侧导航栏 ---------- */
|
|
457
590
|
#nav {
|
|
458
591
|
position: fixed; inset: 0; z-index: 60; display: none;
|
|
459
|
-
background: rgba(
|
|
592
|
+
background: rgba(4, 7, 11, .62);
|
|
460
593
|
}
|
|
461
594
|
#nav.open { display: block; }
|
|
462
595
|
.nav-panel {
|
|
463
596
|
position: absolute; top: 0; bottom: 0; left: 0; width: min(86vw, 350px);
|
|
464
597
|
display: flex; flex-direction: column;
|
|
465
|
-
background: var(--
|
|
598
|
+
background: var(--glass); border-right: 1px solid var(--line);
|
|
466
599
|
padding-top: env(safe-area-inset-top);
|
|
467
600
|
padding-bottom: env(safe-area-inset-bottom);
|
|
468
|
-
|
|
601
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
602
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
603
|
+
/* 原来抽出来时有一条 0.18s 的滑入(`navIn`),2026-09-27 删掉:
|
|
604
|
+
状态变化是瞬时的,抽屉不该表演怎么出现。 */
|
|
469
605
|
}
|
|
470
|
-
@keyframes navIn { from { transform: translateX(-100%); } }
|
|
471
606
|
.nav-head {
|
|
472
607
|
flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
|
|
473
608
|
padding: 12px 12px 12px 16px; border-bottom: 1px solid var(--line);
|
|
@@ -499,19 +634,23 @@
|
|
|
499
634
|
font: inherit; font-size: 14px; text-align: left; cursor: pointer;
|
|
500
635
|
}
|
|
501
636
|
.sess:active { background: var(--panel-2); }
|
|
502
|
-
|
|
637
|
+
/* "当前会话"用左边一条 2px 冰蓝线,不用投影:层次靠细线,不靠阴影。 */
|
|
638
|
+
.sess.cur { background: var(--panel-2); border-left: 2px solid var(--ice); }
|
|
503
639
|
.sess .s-title { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
504
640
|
.sess .s-meta { flex: 0 0 auto; color: var(--muted); font-size: 11.5px; }
|
|
641
|
+
/* 「正在跑」这个点是**状态**,和主屏顶栏那颗是同一种意思,所以用同一个冰蓝。
|
|
642
|
+
这里原来跟着暖金走,结果抽屉一屏能出现三处金(两个点 + 「就在这个工作区」),
|
|
643
|
+
破了"一屏最多两处"。金只留给"该动手的地方"和"当前这一步"。 */
|
|
505
644
|
.sess .s-dot, .ws-head .s-dot {
|
|
506
645
|
flex: 0 0 auto; width: 6px; height: 6px; border-radius: 50%;
|
|
507
|
-
background: var(--
|
|
646
|
+
background: var(--run);
|
|
508
647
|
}
|
|
509
648
|
/* 「新建会话」那一行。跟会话条目同宽、同缩进,但用强调色——
|
|
510
649
|
它不是一个会话,是一个动作。长得跟会话一样会让人以为点进去就是那条会话。 */
|
|
511
650
|
.ws-new {
|
|
512
651
|
display: flex; align-items: center; gap: 6px; width: 100%;
|
|
513
652
|
padding: 10px 14px 10px 30px; background: none; border: none;
|
|
514
|
-
color: var(--
|
|
653
|
+
color: var(--ice); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
|
|
515
654
|
}
|
|
516
655
|
.ws-new:active { background: var(--panel-2); }
|
|
517
656
|
.ws-new[disabled] { color: var(--muted); cursor: default; }
|
|
@@ -521,7 +660,7 @@
|
|
|
521
660
|
.nav-cta {
|
|
522
661
|
display: flex; align-items: center; gap: 6px; width: 100%;
|
|
523
662
|
padding: 12px 14px; background: none; border: none; border-bottom: 1px solid var(--line);
|
|
524
|
-
color: var(--
|
|
663
|
+
color: var(--ice); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
|
|
525
664
|
}
|
|
526
665
|
.nav-cta:active { background: var(--panel-2); }
|
|
527
666
|
|
|
@@ -531,8 +670,8 @@
|
|
|
531
670
|
overflow-x: auto; white-space: nowrap; border-bottom: 1px solid var(--line);
|
|
532
671
|
}
|
|
533
672
|
.crumb button {
|
|
534
|
-
background: none; border: none; color: var(--
|
|
535
|
-
font-size: 13px; padding: 4px 6px; cursor: pointer; border-radius:
|
|
673
|
+
background: none; border: none; color: var(--ice); font: inherit;
|
|
674
|
+
font-size: 13px; padding: 4px 6px; cursor: pointer; border-radius: var(--r);
|
|
536
675
|
}
|
|
537
676
|
.crumb button:active { background: var(--panel-2); }
|
|
538
677
|
.crumb .sep { color: var(--muted); font-size: 12px; }
|
|
@@ -541,8 +680,8 @@
|
|
|
541
680
|
/* 「就选这个目录」——这一屏唯一的主按钮,所以给它实心底。 */
|
|
542
681
|
.pick-here {
|
|
543
682
|
display: block; width: calc(100% - 24px); margin: 10px 12px;
|
|
544
|
-
padding: 11px; border: none; border-radius: var(--
|
|
545
|
-
background: var(--
|
|
683
|
+
padding: 11px; border: none; border-radius: var(--r);
|
|
684
|
+
background: var(--act); color: var(--on-act); font: inherit; font-size: 14px; cursor: pointer;
|
|
546
685
|
}
|
|
547
686
|
.pick-here:active { opacity: .85; }
|
|
548
687
|
.pick-here[disabled] { background: var(--line); color: var(--muted); cursor: default; }
|
|
@@ -553,12 +692,12 @@
|
|
|
553
692
|
.mkdir-row input {
|
|
554
693
|
flex: 1 1 auto; min-width: 0; padding: 9px 10px; font: inherit; font-size: 14px;
|
|
555
694
|
background: var(--panel-2); border: 1px solid var(--line);
|
|
556
|
-
border-radius:
|
|
695
|
+
border-radius: var(--r); color: var(--fg);
|
|
557
696
|
}
|
|
558
697
|
.mkdir-row button {
|
|
559
698
|
flex: 0 0 auto; padding: 9px 12px; font: inherit; font-size: 13px; cursor: pointer;
|
|
560
699
|
background: var(--panel-2); border: 1px solid var(--line);
|
|
561
|
-
border-radius:
|
|
700
|
+
border-radius: var(--r); color: var(--fg);
|
|
562
701
|
}
|
|
563
702
|
.mkdir-row button:active { background: var(--line); }
|
|
564
703
|
|
|
@@ -569,20 +708,22 @@
|
|
|
569
708
|
/* 「这不是全部」:垫在聊天内容最上面,往上翻到顶才看得见,不抢内容。 */
|
|
570
709
|
.history-note {
|
|
571
710
|
margin: 0 0 14px; padding: 8px 12px; border: 1px dashed var(--line);
|
|
572
|
-
border-radius:
|
|
711
|
+
border-radius: var(--r); color: var(--muted); font-size: 12.5px; line-height: 1.6;
|
|
573
712
|
}
|
|
574
713
|
|
|
575
714
|
/* ---------- 设置抽屉 ---------- */
|
|
576
715
|
#settings {
|
|
577
|
-
position: fixed; inset: 0; background:
|
|
716
|
+
position: fixed; inset: 0; background: var(--scrim);
|
|
578
717
|
display: none; align-items: flex-end; z-index: 50;
|
|
579
718
|
}
|
|
580
719
|
#settings.open { display: flex; }
|
|
581
720
|
.sheet {
|
|
582
721
|
width: 100%; max-height: 86vh; overflow-y: auto;
|
|
583
|
-
background: var(--
|
|
722
|
+
background: var(--glass); border-radius: var(--r) var(--r) 0 0;
|
|
584
723
|
padding: 18px 16px calc(env(safe-area-inset-bottom) + 18px);
|
|
585
724
|
border-top: 1px solid var(--line);
|
|
725
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
726
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
586
727
|
}
|
|
587
728
|
.sheet h2 { margin: 0 0 14px; font-size: 16px; }
|
|
588
729
|
.row {
|
|
@@ -595,18 +736,18 @@
|
|
|
595
736
|
/* flex-shrink: 0 不能省。它是弹性项,左边的说明文字一长就会被压缩;
|
|
596
737
|
而它自己带着 overflow: hidden,所以被压掉的那一段不是跑到屏幕外,是**被裁掉**——
|
|
597
738
|
2026-09-25 用户截图里那个「关」字就是这么没的。 */
|
|
598
|
-
.seg { display: flex; flex-shrink: 0; border: 1px solid var(--line); border-radius:
|
|
739
|
+
.seg { display: flex; flex-shrink: 0; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
|
|
599
740
|
.seg button {
|
|
600
741
|
padding: 7px 12px; border: none; background: var(--panel-2); color: var(--muted);
|
|
601
742
|
font-size: 13px; cursor: pointer;
|
|
602
743
|
}
|
|
603
|
-
.seg button.active { background: var(--
|
|
744
|
+
.seg button.active { background: var(--ice); color: var(--on-act); }
|
|
604
745
|
select, .btn {
|
|
605
|
-
padding: 8px 12px; border-radius:
|
|
746
|
+
padding: 8px 12px; border-radius: var(--r); border: 1px solid var(--line);
|
|
606
747
|
background: var(--panel-2); color: var(--fg); font: inherit; font-size: 14px;
|
|
607
748
|
}
|
|
608
749
|
.btn { cursor: pointer; }
|
|
609
|
-
.btn.primary { background: var(--
|
|
750
|
+
.btn.primary { background: var(--act); border-color: var(--act); color: var(--on-act); font-weight: 600; }
|
|
610
751
|
.sheet .foot { margin-top: 18px; display: flex; gap: 10px; }
|
|
611
752
|
.sheet .foot .btn { flex: 1 1 0; text-align: center; }
|
|
612
753
|
|
|
@@ -618,19 +759,20 @@
|
|
|
618
759
|
#gate h1 { font-size: 20px; margin: 0; }
|
|
619
760
|
#gate p { color: var(--muted); font-size: 14px; margin: 0; }
|
|
620
761
|
#gate input {
|
|
621
|
-
padding: 12px 14px; border-radius:
|
|
762
|
+
padding: 12px 14px; border-radius: var(--r); border: 1px solid var(--line);
|
|
622
763
|
background: var(--panel-2); color: var(--fg); font: inherit; font-size: 16px;
|
|
623
764
|
}
|
|
624
765
|
#gate button {
|
|
625
|
-
padding: 13px; border-radius:
|
|
626
|
-
color:
|
|
766
|
+
padding: 13px; border-radius: var(--r); border: none; background: var(--act);
|
|
767
|
+
color: var(--on-act); font-size: 16px; font-weight: 600;
|
|
627
768
|
}
|
|
628
769
|
#gate .err { color: var(--err); font-size: 13px; min-height: 18px; }
|
|
629
770
|
|
|
630
771
|
#toast {
|
|
631
772
|
position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%) translateY(8px);
|
|
632
|
-
background:
|
|
633
|
-
border-radius:
|
|
773
|
+
background: var(--pop); color: var(--fg); padding: 9px 16px;
|
|
774
|
+
border-radius: var(--r); font-size: 13.5px; opacity: 0; pointer-events: none;
|
|
775
|
+
border: 1px solid var(--line);
|
|
634
776
|
transition: opacity .2s, transform .2s; z-index: 200; max-width: 86vw; text-align: center;
|
|
635
777
|
}
|
|
636
778
|
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
@@ -639,25 +781,48 @@
|
|
|
639
781
|
整屏遮住聊天区:手机上一次只专心答一题,答完自动消失。
|
|
640
782
|
之所以遮全屏而不是弹个小条:非技术用户看到"电脑在等你回答"时,
|
|
641
783
|
最怕的是不知道该点哪里;整屏只剩问题本身和按钮,没有第二个选择。 */
|
|
642
|
-
#askCard { position: fixed; inset: 0; z-index: 300; background:
|
|
784
|
+
#askCard { position: fixed; inset: 0; z-index: 300; background: var(--bg);
|
|
643
785
|
display: none; flex-direction: column; padding: 18px 16px calc(18px + env(safe-area-inset-bottom)); overflow-y: auto; }
|
|
644
786
|
#askCard.on { display: flex; }
|
|
645
|
-
#askCard .qhead { font-size: 13px;
|
|
787
|
+
#askCard .qhead { font-size: 13px; color: var(--muted); margin-bottom: 12px; }
|
|
646
788
|
#askCard .qtext { font-size: 18px; line-height: 1.6; margin-bottom: 10px; }
|
|
647
|
-
#askCard .qdetail { font-size: 14px; line-height: 1.65;
|
|
789
|
+
#askCard .qdetail { font-size: 14px; line-height: 1.65; color: var(--muted); margin-bottom: 16px; white-space: pre-wrap; }
|
|
648
790
|
#askCard .opt { display: block; width: 100%; text-align: left; margin: 0 0 10px; padding: 15px 16px;
|
|
649
|
-
font-size: 16px; line-height: 1.5; border-radius:
|
|
650
|
-
background:
|
|
651
|
-
|
|
652
|
-
#askCard .opt
|
|
791
|
+
font-size: 16px; line-height: 1.5; border-radius: var(--r); border: 1px solid var(--line);
|
|
792
|
+
background: var(--panel-2); color: inherit; font-family: inherit; }
|
|
793
|
+
/* 选中的那一条用冰蓝描边:它是"你选的",不是"你要按的主按钮"——主按钮是暖金。 */
|
|
794
|
+
#askCard .opt.sel { border-color: var(--ice); background: rgba(169, 200, 232, .1); }
|
|
795
|
+
#askCard .opt small { display: block; color: var(--muted); font-size: 13px; margin-top: 5px; }
|
|
653
796
|
#askCard textarea { width: 100%; box-sizing: border-box; font-size: 16px; line-height: 1.6;
|
|
654
|
-
border-radius:
|
|
797
|
+
border-radius: var(--r); border: 1px solid var(--line); background: var(--panel-2); color: inherit;
|
|
655
798
|
padding: 12px; font-family: inherit; resize: vertical; }
|
|
656
799
|
#askCard .qfoot { margin-top: auto; display: flex; gap: 10px; padding-top: 16px; }
|
|
657
|
-
#askCard .qfoot button { flex: 1; padding: 15px 8px; font-size: 16px; border-radius:
|
|
658
|
-
border: 1px solid
|
|
659
|
-
|
|
800
|
+
#askCard .qfoot button { flex: 1; padding: 15px 8px; font-size: 16px; border-radius: var(--r);
|
|
801
|
+
border: 1px solid var(--line); background: var(--panel-2); color: inherit; font-family: inherit; }
|
|
802
|
+
/* 这一屏唯一的主按钮,暖金。 */
|
|
803
|
+
#askCard .qfoot button#askNext { background: var(--act); border-color: var(--act); color: var(--on-act); font-weight: 600; }
|
|
804
|
+
/* 没有毛玻璃的浏览器:退回实色面板。别让界面变成一片糊住的半透明。 */
|
|
805
|
+
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
|
|
806
|
+
header, footer, .attach-bar, .cmd-menu, .nav-panel, .sheet { background: var(--panel); }
|
|
807
|
+
}
|
|
808
|
+
/* 细线图标:和回形针、复制按钮那套同一副笔法(1.5px 描边、圆头圆角)。 */
|
|
809
|
+
.icon-btn svg {
|
|
810
|
+
width: 18px; height: 18px; fill: none; stroke: currentColor;
|
|
811
|
+
stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
|
|
812
|
+
}
|
|
660
813
|
</style>
|
|
814
|
+
<script>
|
|
815
|
+
// 主题必须在**首屏画出来之前**定下来,否则浅色手机打开会先闪一下深色底。
|
|
816
|
+
// 所以这一段留在 <head> 里、样式表后面,**别挪到页面底部那段脚本区去**。
|
|
817
|
+
(function () {
|
|
818
|
+
try {
|
|
819
|
+
var pick = localStorage.getItem('dshMiniTheme') || 'dark';
|
|
820
|
+
var dark = !window.matchMedia || window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
821
|
+
document.documentElement.setAttribute('data-theme',
|
|
822
|
+
pick === 'auto' ? (dark ? 'dark' : 'light') : pick);
|
|
823
|
+
} catch (e) { /* 无痕模式下 localStorage 会抛;按默认深色走,不影响页面 */ }
|
|
824
|
+
})();
|
|
825
|
+
</script>
|
|
661
826
|
</head>
|
|
662
827
|
<body>
|
|
663
828
|
|
|
@@ -678,11 +843,11 @@
|
|
|
678
843
|
</div>
|
|
679
844
|
|
|
680
845
|
<header>
|
|
681
|
-
<button class="icon-btn" id="btnNav" aria-label="工作区与会话"
|
|
846
|
+
<button class="icon-btn" id="btnNav" aria-label="工作区与会话"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6h18M3 12h18M3 18h18"/></svg></button>
|
|
682
847
|
<span class="dot" id="dot"></span>
|
|
683
|
-
<span class="brand"
|
|
848
|
+
<span class="brand">极简遥控器</span>
|
|
684
849
|
<span class="status" id="status">连接中…</span>
|
|
685
|
-
<button class="icon-btn" id="btnSettings" aria-label="设置"
|
|
850
|
+
<button class="icon-btn" id="btnSettings" aria-label="设置"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h8M16 7h4M4 17h4M12 17h8"/><circle cx="14" cy="7" r="2.2"/><circle cx="10" cy="17" r="2.2"/></svg></button>
|
|
686
851
|
</header>
|
|
687
852
|
|
|
688
853
|
<!-- 模型与思考强度(2026-09-25 用户要求:手机上要能改每个会话的模型和强度)。
|
|
@@ -746,8 +911,8 @@
|
|
|
746
911
|
<aside class="nav-panel">
|
|
747
912
|
<div class="nav-head">
|
|
748
913
|
<span>工作区与会话</span>
|
|
749
|
-
<button class="icon-btn" id="btnNavRefresh" aria-label="刷新"
|
|
750
|
-
<button class="icon-btn" id="btnNavClose" aria-label="关闭"
|
|
914
|
+
<button class="icon-btn" id="btnNavRefresh" aria-label="刷新"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 11a8 8 0 1 0-2.3 5.7"/><path d="M20 5v6h-6"/></svg></button>
|
|
915
|
+
<button class="icon-btn" id="btnNavClose" aria-label="关闭"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
|
|
751
916
|
</div>
|
|
752
917
|
<div class="nav-body" id="navBody"></div>
|
|
753
918
|
</aside>
|
|
@@ -768,6 +933,20 @@
|
|
|
768
933
|
</div>
|
|
769
934
|
</div>
|
|
770
935
|
|
|
936
|
+
<!-- 外观。深色是原来的样子;浅色的色调跟宣传图(docs/promo.png)统一:
|
|
937
|
+
近白冰蓝的底、深宝蓝的字与状态色、白色卡片。选择记在这台设备上。 -->
|
|
938
|
+
<div class="row">
|
|
939
|
+
<div>
|
|
940
|
+
<div class="label">外观</div>
|
|
941
|
+
<div class="hint">浅色的色调跟宣传图一致</div>
|
|
942
|
+
</div>
|
|
943
|
+
<div class="seg" id="segTheme">
|
|
944
|
+
<button data-theme="dark">深色</button>
|
|
945
|
+
<button data-theme="light">浅色</button>
|
|
946
|
+
<button data-theme="auto">跟随系统</button>
|
|
947
|
+
</div>
|
|
948
|
+
</div>
|
|
949
|
+
|
|
771
950
|
<!-- 权限档位。整块由脚本填:这台电脑有哪些档位是**运行时读**的,一个都不写死。
|
|
772
951
|
服务拿不到时整块不显示——它是附加能力,缺了遥控本身照常。 -->
|
|
773
952
|
<div id="permBlock" hidden>
|
|
@@ -880,6 +1059,9 @@
|
|
|
880
1059
|
var state = {
|
|
881
1060
|
token: params.get('token') || localStorage.getItem('dshMiniToken') || '',
|
|
882
1061
|
mode: localStorage.getItem('dshMiniMode') || DEFAULT_MODE || 'minimal',
|
|
1062
|
+
// 外观:'dark' | 'light' | 'auto'。默认深色——不给老用户换掉现在的样子;
|
|
1063
|
+
// 要浅色或跟着系统走,去设置页「外观」点一下。
|
|
1064
|
+
theme: localStorage.getItem('dshMiniTheme') || 'dark',
|
|
883
1065
|
sound: localStorage.getItem('dshMiniSound') !== 'off',
|
|
884
1066
|
// 锁屏也能提醒(系统通知)。默认关着——它要用户主动点一下才会申请权限,
|
|
885
1067
|
// 不能替他决定。明文连接下这一项永远是空转的,见下面「锁屏也能提醒」那一段。
|
|
@@ -965,6 +1147,18 @@
|
|
|
965
1147
|
return CODE_SLOT + (codes.length - 1) + CODE_SLOT;
|
|
966
1148
|
});
|
|
967
1149
|
out = out
|
|
1150
|
+
// 图片:。地址两种写法——
|
|
1151
|
+
// ① 完整 http(s) 链接:原样用,手机直接去那个网站取图;
|
|
1152
|
+
// ② 一个名字:走本机的图片通道 /mini/art/<名字>.webp,跟立绘同一条路、
|
|
1153
|
+
// 同一样要密码,也只认 lib/art/ 下「小写字母数字连字符 + .webp」的文件名。
|
|
1154
|
+
// 想让手机看到电脑上的图,把图放进 lib/art/、名字以 out- 开头即可。
|
|
1155
|
+
// 必须排在下面那条链接规则前面:否则 `` 里的 `[x](y)` 会先被链接规则
|
|
1156
|
+
// 吃掉,只剩下一个光秃秃的感叹号。
|
|
1157
|
+
.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g, function (_, alt, src) {
|
|
1158
|
+
var url = /^https?:\/\//.test(src) ? src : artUrl(src.replace(/\.webp$/, ''));
|
|
1159
|
+
return '<img class="md-img" src="' + url + '" alt="' + alt + '"'
|
|
1160
|
+
+ ' loading="lazy" referrerpolicy="no-referrer">';
|
|
1161
|
+
})
|
|
968
1162
|
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
|
969
1163
|
.replace(/(^|[^*\w])\*([^*\n]+)\*/g, '$1<em>$2</em>')
|
|
970
1164
|
.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,
|
|
@@ -1571,16 +1765,31 @@
|
|
|
1571
1765
|
function paintQueue() {
|
|
1572
1766
|
var el = $('queue');
|
|
1573
1767
|
var list = state.queued || [];
|
|
1768
|
+
// 刻度尺上第一个点永远是**正在跑的那条**,后面每个点对应一条真排在队里的指令。
|
|
1769
|
+
//
|
|
1770
|
+
// 2026-09-27 用户裁决:**队列是空的就整块收起来,不显示。**
|
|
1771
|
+
// 上一版这里是「只要在跑就留着」,理由是一个金点表示"你这一轮正是第 1 步";
|
|
1772
|
+
// 用户实际看到的是「排队中 0 条」配一个孤零零的点,判定为噪音。撤销。
|
|
1773
|
+
// (上面那段注释里"哪怕只有一格,秩序也在"的说法同样作废。)
|
|
1574
1774
|
if (!list.length) { el.hidden = true; el.innerHTML = ''; return; }
|
|
1575
1775
|
el.hidden = false;
|
|
1776
|
+
// 最多画 12 个点:再长这条尺子就成噪点了,超出缀一个省略号。
|
|
1777
|
+
var nodes = '<div class="q-node cur"><i></i><b>1</b></div>';
|
|
1778
|
+
var shown = Math.min(list.length, 11);
|
|
1779
|
+
for (var n = 0; n < shown; n += 1) {
|
|
1780
|
+
nodes += '<div class="q-node"><i></i><b>' + (n + 2) + '</b></div>';
|
|
1781
|
+
}
|
|
1782
|
+
if (list.length > shown) nodes += '<div class="q-node"><i></i><b>…</b></div>';
|
|
1576
1783
|
var rows = '';
|
|
1577
1784
|
for (var i = 0; i < list.length; i += 1) {
|
|
1578
1785
|
rows += '<div class="q-row">'
|
|
1579
1786
|
+ '<span class="q-text">' + escapeHtml(list[i].text) + '</span>'
|
|
1580
1787
|
+ '<button class="q-drop" type="button" data-drop="' + escapeHtml(list[i].id) + '"'
|
|
1581
|
-
+ ' aria-label="撤掉这条"
|
|
1788
|
+
+ ' aria-label="撤掉这条"><svg viewBox="0 0 24 24" aria-hidden="true">'
|
|
1789
|
+
+ '<path d="M6 6l12 12M18 6L6 18"/></svg></button></div>';
|
|
1582
1790
|
}
|
|
1583
|
-
el.innerHTML = '<div class="q-head">排队中 ' + list.length + ' 条 · 跑完这轮就轮到它们</div>'
|
|
1791
|
+
el.innerHTML = '<div class="q-head">排队中 ' + list.length + ' 条 · 跑完这轮就轮到它们</div>'
|
|
1792
|
+
+ '<div class="q-scale">' + nodes + '</div>' + rows;
|
|
1584
1793
|
}
|
|
1585
1794
|
|
|
1586
1795
|
/**
|
|
@@ -3110,6 +3319,39 @@
|
|
|
3110
3319
|
syncSeg();
|
|
3111
3320
|
});
|
|
3112
3321
|
});
|
|
3322
|
+
|
|
3323
|
+
// ---------------- 外观(深色 / 浅色 / 跟随系统) ----------------
|
|
3324
|
+
// 只改 <html> 上的 data-theme,样式表里两套令牌各管各的。这里不碰任何具体颜色,
|
|
3325
|
+
// 免得以后加第三套主题还要回来改这一段。
|
|
3326
|
+
// 首屏那次由 <head> 里那一小段负责(不然会闪);这一段管切换和"跟着系统变"。
|
|
3327
|
+
function resolvedTheme() {
|
|
3328
|
+
if (state.theme !== 'auto') return state.theme;
|
|
3329
|
+
var dark = !window.matchMedia || window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
3330
|
+
return dark ? 'dark' : 'light';
|
|
3331
|
+
}
|
|
3332
|
+
function applyTheme() {
|
|
3333
|
+
var use = resolvedTheme() === 'light' ? 'light' : 'dark';
|
|
3334
|
+
document.documentElement.setAttribute('data-theme', use);
|
|
3335
|
+
// 手机状态栏那块颜色也跟着走,否则浅色页配一条深色状态栏,像没画完。
|
|
3336
|
+
var meta = document.querySelector('meta[name="theme-color"]');
|
|
3337
|
+
if (meta) meta.setAttribute('content', use === 'light' ? '#eaf3fc' : '#0a0f16');
|
|
3338
|
+
}
|
|
3339
|
+
Array.prototype.forEach.call($('segTheme').children, function (btn) {
|
|
3340
|
+
btn.addEventListener('click', function () {
|
|
3341
|
+
state.theme = btn.dataset.theme;
|
|
3342
|
+
localStorage.setItem('dshMiniTheme', state.theme);
|
|
3343
|
+
applyTheme();
|
|
3344
|
+
syncSeg();
|
|
3345
|
+
});
|
|
3346
|
+
});
|
|
3347
|
+
if (window.matchMedia) {
|
|
3348
|
+
var themeMq = window.matchMedia('(prefers-color-scheme: dark)');
|
|
3349
|
+
var onThemeMq = function () { if (state.theme === 'auto') applyTheme(); };
|
|
3350
|
+
if (themeMq.addEventListener) themeMq.addEventListener('change', onThemeMq);
|
|
3351
|
+
else if (themeMq.addListener) themeMq.addListener(onThemeMq);
|
|
3352
|
+
}
|
|
3353
|
+
applyTheme(); // 补上首屏那次没做的一件事:把状态栏颜色对齐
|
|
3354
|
+
|
|
3113
3355
|
function syncSeg() {
|
|
3114
3356
|
Array.prototype.forEach.call($('segMode').children, function (b) {
|
|
3115
3357
|
b.classList.toggle('active', b.dataset.mode === state.mode);
|
|
@@ -3117,6 +3359,9 @@
|
|
|
3117
3359
|
Array.prototype.forEach.call($('segSound').children, function (b) {
|
|
3118
3360
|
b.classList.toggle('active', (b.dataset.sound === 'on') === state.sound);
|
|
3119
3361
|
});
|
|
3362
|
+
Array.prototype.forEach.call($('segTheme').children, function (b) {
|
|
3363
|
+
b.classList.toggle('active', b.dataset.theme === state.theme);
|
|
3364
|
+
});
|
|
3120
3365
|
}
|
|
3121
3366
|
|
|
3122
3367
|
// 会话切换挪到左侧导航栏了(原来这里是设置里的下拉框)。
|
|
@@ -3410,14 +3655,14 @@
|
|
|
3410
3655
|
+ 'color:inherit;padding:11px 2px;border-bottom:1px solid var(--line,#333)'
|
|
3411
3656
|
var HEAD = 'padding:14px 2px 4px;font-size:12px;color:var(--dim,#888)'
|
|
3412
3657
|
var CHIP = 'margin:0 6px 6px 0;padding:5px 13px;border:1px solid var(--line,#444);'
|
|
3413
|
-
+ 'border-radius:
|
|
3658
|
+
+ 'border-radius:var(--r,2px);background:none;font:inherit;color:inherit;font-size:13px'
|
|
3414
3659
|
|
|
3415
3660
|
// 面板用代码建出来、挂在 body 末尾,而不是写进页面结构里——这样这一整块的
|
|
3416
3661
|
// 改动全部落在脚本内部,不用动 HTML,也就不会碰到别的部分。
|
|
3417
|
-
var mask = el('div', 'position:fixed;inset:0;background:
|
|
3662
|
+
var mask = el('div', 'position:fixed;inset:0;background:var(--scrim);z-index:69;display:none')
|
|
3418
3663
|
var sheet = el('div', 'position:fixed;left:0;right:0;bottom:0;z-index:70;display:none;'
|
|
3419
3664
|
+ 'max-height:72vh;overflow-y:auto;background:var(--bg,#1b1b1b);'
|
|
3420
|
-
+ 'border-top:1px solid var(--line,#444);border-radius:
|
|
3665
|
+
+ 'border-top:1px solid var(--line,#444);border-radius:var(--r,2px) var(--r,2px) 0 0;'
|
|
3421
3666
|
+ 'padding:10px 14px calc(16px + env(safe-area-inset-bottom))')
|
|
3422
3667
|
document.body.appendChild(mask)
|
|
3423
3668
|
document.body.appendChild(sheet)
|