@liguoshuai/pi-web-chat 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/bin/pi-web-chat.js +67 -0
- package/package.json +47 -0
- package/public/app.js +860 -0
- package/public/index.html +68 -0
- package/public/style.css +349 -0
- package/server.js +322 -0
|
@@ -0,0 +1,68 @@
|
|
|
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.0">
|
|
6
|
+
<title>pi · Chat</title>
|
|
7
|
+
<link rel="stylesheet" href="/style.css">
|
|
8
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ctext y='20' font-size='20'%3Eπ%3C/text%3E%3C/svg%3E">
|
|
9
|
+
</head>
|
|
10
|
+
<body data-cwd="">
|
|
11
|
+
<div class="app">
|
|
12
|
+
<!-- Sidebar -->
|
|
13
|
+
<aside class="sidebar">
|
|
14
|
+
<div class="sidebar-top">
|
|
15
|
+
<button class="btn-new" id="btnNew" title="新对话">
|
|
16
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
|
|
17
|
+
<span>新对话</span>
|
|
18
|
+
</button>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="sidebar-search">
|
|
21
|
+
<input id="sidebarSearch" type="text" placeholder="搜索会话…">
|
|
22
|
+
</div>
|
|
23
|
+
<div class="session-list" id="sessionList"></div>
|
|
24
|
+
<div class="sidebar-bottom">
|
|
25
|
+
<div><span id="connDot" style="color: var(--danger);">●</span> <span id="connLabel">连接中…</span></div>
|
|
26
|
+
<div style="margin-top:4px;"><a href="https://pi.dev" target="_blank" rel="noopener">pi.dev</a></div>
|
|
27
|
+
</div>
|
|
28
|
+
</aside>
|
|
29
|
+
|
|
30
|
+
<!-- Main -->
|
|
31
|
+
<main class="main">
|
|
32
|
+
<div class="topbar">
|
|
33
|
+
<div class="session-name" id="topSessionName">新对话</div>
|
|
34
|
+
<button class="btn-ghost" id="modelPillWrap" title="工作目录">
|
|
35
|
+
<span id="cwdPill">~</span>
|
|
36
|
+
</button>
|
|
37
|
+
<div style="position:relative;">
|
|
38
|
+
<button class="model-pill" id="modelPill">选择模型</button>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="model-menu" id="modelMenu"></div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="chat" id="chat">
|
|
44
|
+
<div id="emptyState" class="empty-state" style="display:flex;">
|
|
45
|
+
<div class="logo">π</div>
|
|
46
|
+
<h1>有什么可以帮你?</h1>
|
|
47
|
+
<p>我是 <strong>pi</strong> 编程助手,可以读写文件、运行命令、改代码。在下面输入你的需求,或选择左侧的历史会话继续。</p>
|
|
48
|
+
<div class="suggestions">
|
|
49
|
+
<div class="chip" data-prompt="列出当前目录下的所有文件,并告诉我这是什么项目">列出当前目录文件</div>
|
|
50
|
+
<div class="chip" data-prompt="阅读 README 或主要源文件,然后用一段话总结这个项目是做什么的">总结这个项目</div>
|
|
51
|
+
<div class="chip" data-prompt="帮我看看当前目录有没有什么可以改进的地方">代码审查</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="chat-inner" id="chat-inner"></div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="composer">
|
|
58
|
+
<div class="composer-inner" id="composerInner">
|
|
59
|
+
<textarea id="composer" rows="1" placeholder="给 pi 发消息… (Enter 发送,Shift+Enter 换行)"></textarea>
|
|
60
|
+
<button class="send-btn" id="sendBtn" title="发送">↑</button>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="composer-hint">pi 会执行命令与读写你的文件 —— 请注意操作内容。</div>
|
|
63
|
+
</div>
|
|
64
|
+
</main>
|
|
65
|
+
</div>
|
|
66
|
+
<script src="/app.js"></script>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
package/public/style.css
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg: #212121;
|
|
3
|
+
--bg-sidebar: #171717;
|
|
4
|
+
--bg-hover: #2a2a2a;
|
|
5
|
+
--bg-input: #2f2f2f;
|
|
6
|
+
--bg-user-bubble: #2f2f2f;
|
|
7
|
+
--bg-assistant: transparent;
|
|
8
|
+
--border: #3a3a3a;
|
|
9
|
+
--text: #ececec;
|
|
10
|
+
--text-muted: #9b9b9b;
|
|
11
|
+
--text-dim: #6f6f6f;
|
|
12
|
+
--accent: #10a37f;
|
|
13
|
+
--accent-hover: #0e8c6d;
|
|
14
|
+
--user-text: #ececec;
|
|
15
|
+
--tool-bg: #1a1a1a;
|
|
16
|
+
--tool-border: #333;
|
|
17
|
+
--thinking-bg: #1c1c1c;
|
|
18
|
+
--thinking-border: #444;
|
|
19
|
+
--danger: #ef4444;
|
|
20
|
+
--radius: 14px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
24
|
+
html, body { height: 100%; }
|
|
25
|
+
body {
|
|
26
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
27
|
+
background: var(--bg);
|
|
28
|
+
color: var(--text);
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.app {
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-template-columns: 260px 1fr;
|
|
35
|
+
height: 100vh;
|
|
36
|
+
width: 100vw;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* ---------- Sidebar ---------- */
|
|
40
|
+
.sidebar {
|
|
41
|
+
background: var(--bg-sidebar);
|
|
42
|
+
border-right: 1px solid var(--border);
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
min-height: 0;
|
|
46
|
+
}
|
|
47
|
+
.sidebar-top {
|
|
48
|
+
padding: 10px;
|
|
49
|
+
display: flex;
|
|
50
|
+
gap: 8px;
|
|
51
|
+
align-items: center;
|
|
52
|
+
}
|
|
53
|
+
.btn-new {
|
|
54
|
+
flex: 1;
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: 8px;
|
|
58
|
+
justify-content: flex-start;
|
|
59
|
+
padding: 10px 12px;
|
|
60
|
+
border: 1px solid var(--border);
|
|
61
|
+
border-radius: var(--radius);
|
|
62
|
+
background: transparent;
|
|
63
|
+
color: var(--text);
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
font-size: 14px;
|
|
66
|
+
transition: background .15s;
|
|
67
|
+
}
|
|
68
|
+
.btn-new:hover { background: var(--bg-hover); }
|
|
69
|
+
.sidebar-search {
|
|
70
|
+
padding: 0 10px 8px;
|
|
71
|
+
}
|
|
72
|
+
.sidebar-search input {
|
|
73
|
+
width: 100%;
|
|
74
|
+
padding: 8px 12px;
|
|
75
|
+
background: var(--bg);
|
|
76
|
+
border: 1px solid var(--border);
|
|
77
|
+
border-radius: 10px;
|
|
78
|
+
color: var(--text);
|
|
79
|
+
font-size: 13px;
|
|
80
|
+
outline: none;
|
|
81
|
+
}
|
|
82
|
+
.sidebar-search input:focus { border-color: var(--text-dim); }
|
|
83
|
+
|
|
84
|
+
.session-list {
|
|
85
|
+
flex: 1;
|
|
86
|
+
overflow-y: auto;
|
|
87
|
+
padding: 4px 8px 16px;
|
|
88
|
+
}
|
|
89
|
+
.session-item {
|
|
90
|
+
padding: 9px 10px;
|
|
91
|
+
border-radius: 10px;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
font-size: 13px;
|
|
94
|
+
color: var(--text);
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: flex-start;
|
|
97
|
+
gap: 8px;
|
|
98
|
+
margin-bottom: 2px;
|
|
99
|
+
transition: background .12s;
|
|
100
|
+
word-break: break-word;
|
|
101
|
+
}
|
|
102
|
+
.session-item:hover { background: var(--bg-hover); }
|
|
103
|
+
.session-item.active { background: var(--bg-hover); }
|
|
104
|
+
.session-item .dot { color: var(--text-dim); flex-shrink: 0; margin-top: 2px; }
|
|
105
|
+
.session-item .title { flex: 1; line-height: 1.35; }
|
|
106
|
+
.session-item .meta {
|
|
107
|
+
font-size: 11px; color: var(--text-dim); margin-top: 3px;
|
|
108
|
+
}
|
|
109
|
+
.sidebar-empty { color: var(--text-dim); font-size: 13px; padding: 20px 12px; text-align: center; }
|
|
110
|
+
|
|
111
|
+
.sidebar-bottom {
|
|
112
|
+
border-top: 1px solid var(--border);
|
|
113
|
+
padding: 10px;
|
|
114
|
+
font-size: 12px;
|
|
115
|
+
color: var(--text-muted);
|
|
116
|
+
}
|
|
117
|
+
.sidebar-bottom a { color: var(--text-muted); text-decoration: none; }
|
|
118
|
+
.sidebar-bottom a:hover { color: var(--text); }
|
|
119
|
+
|
|
120
|
+
/* ---------- Main ---------- */
|
|
121
|
+
.main {
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: column;
|
|
124
|
+
min-height: 0;
|
|
125
|
+
min-width: 0;
|
|
126
|
+
position: relative;
|
|
127
|
+
}
|
|
128
|
+
.topbar {
|
|
129
|
+
height: 48px;
|
|
130
|
+
border-bottom: 1px solid var(--border);
|
|
131
|
+
display: flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
padding: 0 14px;
|
|
134
|
+
gap: 10px;
|
|
135
|
+
background: var(--bg);
|
|
136
|
+
z-index: 2;
|
|
137
|
+
}
|
|
138
|
+
.topbar .session-name {
|
|
139
|
+
font-size: 14px;
|
|
140
|
+
color: var(--text);
|
|
141
|
+
font-weight: 500;
|
|
142
|
+
flex: 1;
|
|
143
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
144
|
+
}
|
|
145
|
+
.model-pill {
|
|
146
|
+
font-size: 12px; color: var(--text-muted);
|
|
147
|
+
border: 1px solid var(--border); border-radius: 999px;
|
|
148
|
+
padding: 4px 10px; cursor: pointer; background: var(--bg-input);
|
|
149
|
+
}
|
|
150
|
+
.model-pill:hover { color: var(--text); }
|
|
151
|
+
.btn-ghost {
|
|
152
|
+
background: transparent; border: none; color: var(--text-muted);
|
|
153
|
+
cursor: pointer; font-size: 13px; padding: 6px 8px; border-radius: 8px;
|
|
154
|
+
}
|
|
155
|
+
.btn-ghost:hover { background: var(--bg-hover); color: var(--text); }
|
|
156
|
+
|
|
157
|
+
/* ---------- Chat ---------- */
|
|
158
|
+
.chat {
|
|
159
|
+
flex: 1;
|
|
160
|
+
overflow-y: auto;
|
|
161
|
+
scroll-behavior: smooth;
|
|
162
|
+
padding: 20px 0 24px;
|
|
163
|
+
}
|
|
164
|
+
.chat-inner {
|
|
165
|
+
max-width: 820px;
|
|
166
|
+
margin: 0 auto;
|
|
167
|
+
padding: 0 20px;
|
|
168
|
+
display: flex;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
gap: 22px;
|
|
171
|
+
}
|
|
172
|
+
.msg { display: flex; flex-direction: column; gap: 8px; animation: fade .18s ease; }
|
|
173
|
+
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; } }
|
|
174
|
+
|
|
175
|
+
.msg.user {
|
|
176
|
+
align-items: flex-end;
|
|
177
|
+
}
|
|
178
|
+
.msg.user .bubble {
|
|
179
|
+
background: var(--bg-user-bubble);
|
|
180
|
+
color: var(--user-text);
|
|
181
|
+
padding: 11px 16px;
|
|
182
|
+
border-radius: 18px;
|
|
183
|
+
max-width: 80%;
|
|
184
|
+
white-space: pre-wrap;
|
|
185
|
+
word-break: break-word;
|
|
186
|
+
line-height: 1.55;
|
|
187
|
+
font-size: 15px;
|
|
188
|
+
}
|
|
189
|
+
.msg.assistant { align-items: stretch; }
|
|
190
|
+
.msg.assistant .role-tag {
|
|
191
|
+
font-size: 12px; color: var(--text-dim); font-weight: 600; letter-spacing: .3px;
|
|
192
|
+
display: flex; align-items: center; gap: 6px;
|
|
193
|
+
}
|
|
194
|
+
.msg.assistant .content {
|
|
195
|
+
font-size: 15px; line-height: 1.65; color: var(--text);
|
|
196
|
+
max-width: 100%; min-width: 0;
|
|
197
|
+
}
|
|
198
|
+
.msg.assistant .content p { margin-bottom: 10px; }
|
|
199
|
+
.msg.assistant .content p:last-child { margin-bottom: 0; }
|
|
200
|
+
.msg.assistant .content pre {
|
|
201
|
+
background: #0d0d0d; border: 1px solid var(--border);
|
|
202
|
+
border-radius: 10px; padding: 12px 14px; overflow-x: auto;
|
|
203
|
+
margin: 10px 0; font-size: 13px; line-height: 1.5;
|
|
204
|
+
font-family: "SF Mono", Menlo, Consolas, monospace;
|
|
205
|
+
}
|
|
206
|
+
.msg.assistant .content code {
|
|
207
|
+
font-family: "SF Mono", Menlo, Consolas, monospace;
|
|
208
|
+
font-size: 0.88em;
|
|
209
|
+
background: #2a2a2a; padding: 1px 5px; border-radius: 4px;
|
|
210
|
+
}
|
|
211
|
+
.msg.assistant .content pre code { background: transparent; padding: 0; }
|
|
212
|
+
.msg.assistant .content ul, .msg.assistant .content ol { margin: 6px 0 10px 22px; }
|
|
213
|
+
.msg.assistant .content li { margin: 3px 0; }
|
|
214
|
+
.msg.assistant .content h1, .msg.assistant .content h2, .msg.assistant .content h3 {
|
|
215
|
+
margin: 14px 0 8px; line-height: 1.3;
|
|
216
|
+
}
|
|
217
|
+
.msg.assistant .content h1 { font-size: 20px; }
|
|
218
|
+
.msg.assistant .content h2 { font-size: 18px; }
|
|
219
|
+
.msg.assistant .content h3 { font-size: 16px; }
|
|
220
|
+
.msg.assistant .content a { color: #4ea1ff; }
|
|
221
|
+
.msg.assistant .content table {
|
|
222
|
+
border-collapse: collapse; margin: 10px 0; font-size: 13px;
|
|
223
|
+
}
|
|
224
|
+
.msg.assistant .content th, .msg.assistant .content td {
|
|
225
|
+
border: 1px solid var(--border); padding: 6px 10px;
|
|
226
|
+
}
|
|
227
|
+
.msg.assistant .content blockquote {
|
|
228
|
+
border-left: 3px solid var(--border); padding-left: 12px; color: var(--text-muted);
|
|
229
|
+
margin: 8px 0;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Tool call blocks */
|
|
233
|
+
.tool-block {
|
|
234
|
+
background: var(--tool-bg);
|
|
235
|
+
border: 1px solid var(--tool-border);
|
|
236
|
+
border-radius: 10px;
|
|
237
|
+
margin: 8px 0;
|
|
238
|
+
font-size: 13px;
|
|
239
|
+
overflow: hidden;
|
|
240
|
+
}
|
|
241
|
+
.tool-head {
|
|
242
|
+
display: flex; align-items: center; gap: 8px;
|
|
243
|
+
padding: 8px 12px; cursor: pointer; user-select: none;
|
|
244
|
+
background: #1f1f1f;
|
|
245
|
+
}
|
|
246
|
+
.tool-head .ic { color: var(--accent); font-size: 12px; }
|
|
247
|
+
.tool-head .name { font-weight: 600; color: var(--text); }
|
|
248
|
+
.tool-head .args { color: var(--text-muted); font-family: monospace; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
249
|
+
.tool-head .state { font-size: 11px; color: var(--text-dim); padding: 2px 8px; background: #2a2a2a; border-radius: 999px; }
|
|
250
|
+
.tool-head .state.error { color: var(--danger); background: #3a1a1a; }
|
|
251
|
+
.tool-body {
|
|
252
|
+
padding: 10px 12px; border-top: 1px solid var(--tool-border);
|
|
253
|
+
max-height: 280px; overflow-y: auto;
|
|
254
|
+
white-space: pre-wrap; word-break: break-word;
|
|
255
|
+
font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 12px; color: #cfcfcf;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Thinking blocks */
|
|
259
|
+
.thinking-block {
|
|
260
|
+
background: var(--thinking-bg);
|
|
261
|
+
border: 1px solid var(--thinking-border);
|
|
262
|
+
border-radius: 10px; margin: 8px 0; font-size: 13px; overflow: hidden;
|
|
263
|
+
}
|
|
264
|
+
.thinking-head {
|
|
265
|
+
padding: 8px 12px; cursor: pointer; user-select: none; display: flex; gap: 8px; align-items: center;
|
|
266
|
+
color: var(--text-muted);
|
|
267
|
+
}
|
|
268
|
+
.thinking-body {
|
|
269
|
+
padding: 10px 12px; border-top: 1px solid var(--thinking-border);
|
|
270
|
+
font-style: italic; color: var(--text-muted); max-height: 240px; overflow-y: auto;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.typing-cursor::after {
|
|
274
|
+
content: "▋"; display: inline-block; margin-left: 2px;
|
|
275
|
+
animation: blink 1s steps(2) infinite; color: var(--accent);
|
|
276
|
+
}
|
|
277
|
+
@keyframes blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
|
|
278
|
+
|
|
279
|
+
/* ---------- Empty state ---------- */
|
|
280
|
+
.empty-state {
|
|
281
|
+
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
282
|
+
height: 100%; text-align: center; color: var(--text-muted);
|
|
283
|
+
gap: 14px; padding: 30px;
|
|
284
|
+
}
|
|
285
|
+
.empty-state .logo { font-size: 40px; }
|
|
286
|
+
.empty-state h1 { font-size: 28px; font-weight: 500; color: var(--text); }
|
|
287
|
+
.empty-state p { font-size: 15px; max-width: 480px; }
|
|
288
|
+
.suggestions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 8px; }
|
|
289
|
+
.suggestions .chip {
|
|
290
|
+
border: 1px solid var(--border); border-radius: 999px; padding: 9px 16px;
|
|
291
|
+
font-size: 13px; color: var(--text-muted); background: var(--bg-input); cursor: pointer;
|
|
292
|
+
transition: all .15s;
|
|
293
|
+
}
|
|
294
|
+
.suggestions .chip:hover { border-color: var(--text-dim); color: var(--text); }
|
|
295
|
+
|
|
296
|
+
/* ---------- Composer ---------- */
|
|
297
|
+
.composer {
|
|
298
|
+
padding: 14px 20px 18px;
|
|
299
|
+
background: var(--bg);
|
|
300
|
+
border-top: 1px solid transparent;
|
|
301
|
+
}
|
|
302
|
+
.composer-inner {
|
|
303
|
+
max-width: 820px; margin: 0 auto;
|
|
304
|
+
background: var(--bg-input);
|
|
305
|
+
border: 1px solid var(--border);
|
|
306
|
+
border-radius: 24px;
|
|
307
|
+
padding: 6px 6px 6px 18px;
|
|
308
|
+
display: flex; align-items: flex-end; gap: 8px;
|
|
309
|
+
transition: border-color .15s;
|
|
310
|
+
}
|
|
311
|
+
.composer-inner:focus-within { border-color: var(--text-dim); }
|
|
312
|
+
.composer-inner.aborting { border-color: var(--danger); }
|
|
313
|
+
.composer textarea {
|
|
314
|
+
flex: 1; background: transparent; border: none; outline: none; resize: none;
|
|
315
|
+
color: var(--text); font-family: inherit; font-size: 15px; line-height: 1.5;
|
|
316
|
+
padding: 12px 0; max-height: 220px; min-height: 24px;
|
|
317
|
+
}
|
|
318
|
+
.composer .send-btn {
|
|
319
|
+
width: 38px; height: 38px; border-radius: 50%; border: none; cursor: pointer;
|
|
320
|
+
background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center;
|
|
321
|
+
flex-shrink: 0; transition: background .15s, opacity .15s;
|
|
322
|
+
}
|
|
323
|
+
.composer .send-btn:disabled { background: #3a3a3a; color: #6f6f6f; cursor: not-allowed; }
|
|
324
|
+
.composer .send-btn.stop { background: var(--danger); }
|
|
325
|
+
.composer-hint {
|
|
326
|
+
text-align: center; color: var(--text-dim); font-size: 11px; margin-top: 8px; max-width: 820px; margin-left: auto; margin-right: auto;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Scrollbar */
|
|
330
|
+
::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
331
|
+
::-webkit-scrollbar-thumb { background: #3a3a3a; border-radius: 8px; }
|
|
332
|
+
::-webkit-scrollbar-thumb:hover { background: #4a4a4a; }
|
|
333
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
334
|
+
|
|
335
|
+
/* Model selector dropdown */
|
|
336
|
+
.model-menu {
|
|
337
|
+
position: absolute; top: 48px; right: 14px;
|
|
338
|
+
background: var(--bg-input); border: 1px solid var(--border);
|
|
339
|
+
border-radius: 12px; padding: 8px; width: 320px; max-height: 360px; overflow-y: auto;
|
|
340
|
+
box-shadow: 0 8px 24px rgba(0,0,0,.4); z-index: 10; display: none;
|
|
341
|
+
}
|
|
342
|
+
.model-menu.open { display: block; }
|
|
343
|
+
.model-menu .group-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; padding: 6px 8px 2px; }
|
|
344
|
+
.model-menu .opt {
|
|
345
|
+
padding: 8px 10px; border-radius: 8px; cursor: pointer; font-size: 13px; color: var(--text);
|
|
346
|
+
}
|
|
347
|
+
.model-menu .opt:hover { background: var(--bg-hover); }
|
|
348
|
+
.model-menu .opt.active { background: var(--bg-hover); }
|
|
349
|
+
.model-menu .opt .check { color: var(--accent); margin-right: 6px; }
|