@hirohsu/user-web-feedback 2.6.0

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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +953 -0
  3. package/dist/cli.cjs +95778 -0
  4. package/dist/index.cjs +92818 -0
  5. package/dist/static/app.js +385 -0
  6. package/dist/static/components/navbar.css +406 -0
  7. package/dist/static/components/navbar.html +49 -0
  8. package/dist/static/components/navbar.js +211 -0
  9. package/dist/static/dashboard.css +495 -0
  10. package/dist/static/dashboard.html +95 -0
  11. package/dist/static/dashboard.js +540 -0
  12. package/dist/static/favicon.svg +27 -0
  13. package/dist/static/index.html +541 -0
  14. package/dist/static/logs.html +376 -0
  15. package/dist/static/logs.js +442 -0
  16. package/dist/static/mcp-settings.html +797 -0
  17. package/dist/static/mcp-settings.js +884 -0
  18. package/dist/static/modules/app-core.js +124 -0
  19. package/dist/static/modules/conversation-panel.js +247 -0
  20. package/dist/static/modules/feedback-handler.js +1420 -0
  21. package/dist/static/modules/image-handler.js +155 -0
  22. package/dist/static/modules/log-viewer.js +296 -0
  23. package/dist/static/modules/mcp-manager.js +474 -0
  24. package/dist/static/modules/prompt-manager.js +364 -0
  25. package/dist/static/modules/settings-manager.js +299 -0
  26. package/dist/static/modules/socket-manager.js +170 -0
  27. package/dist/static/modules/state-manager.js +352 -0
  28. package/dist/static/modules/timer-controller.js +243 -0
  29. package/dist/static/modules/ui-helpers.js +246 -0
  30. package/dist/static/settings.html +355 -0
  31. package/dist/static/settings.js +425 -0
  32. package/dist/static/socket.io.min.js +7 -0
  33. package/dist/static/style.css +2157 -0
  34. package/dist/static/terminals.html +357 -0
  35. package/dist/static/terminals.js +321 -0
  36. package/package.json +91 -0
@@ -0,0 +1,2157 @@
1
+ /* ============ 全局樣式 ============ */
2
+
3
+ * {
4
+ margin: 0;
5
+ padding: 0;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ :root {
10
+ /* VS Code 深色主題顏色 */
11
+ --bg-primary: #1e1e1e;
12
+ --bg-secondary: #252526;
13
+ --bg-tertiary: #2d2d30;
14
+ --bg-hover: #37373d;
15
+ --border-color: #3e3e42;
16
+ --text-primary: #cccccc;
17
+ --text-secondary: #969696;
18
+ --text-muted: #6a6a6a;
19
+ --accent-blue: #007acc;
20
+ --accent-green: #4ec9b0;
21
+ --accent-red: #f48771;
22
+ --accent-orange: #ce9178;
23
+ --accent-yellow: #dcdcaa;
24
+
25
+ /* 間距 */
26
+ --spacing-xs: 4px;
27
+ --spacing-sm: 8px;
28
+ --spacing-md: 16px;
29
+ --spacing-lg: 24px;
30
+ --spacing-xl: 32px;
31
+
32
+ /* 圓角 */
33
+ --radius-sm: 4px;
34
+ --radius-md: 8px;
35
+ --radius-lg: 12px;
36
+
37
+ /* 陰影 */
38
+ --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.2);
39
+ --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.3);
40
+ --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.4);
41
+ }
42
+
43
+ body {
44
+ font-family: "Segoe UI", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
45
+ background: var(--bg-primary);
46
+ color: var(--text-primary);
47
+ font-size: 13px;
48
+ line-height: 1.5;
49
+ overflow: hidden;
50
+ }
51
+
52
+ /* ============ Dashboard 導航連結 ============ */
53
+
54
+ .dashboard-nav-link {
55
+ position: fixed;
56
+ top: 12px;
57
+ left: 12px;
58
+ display: inline-flex;
59
+ align-items: center;
60
+ gap: 6px;
61
+ padding: 8px 14px;
62
+ background: var(--bg-secondary);
63
+ border: 1px solid var(--border-color);
64
+ border-radius: var(--radius-md);
65
+ color: var(--text-primary);
66
+ text-decoration: none;
67
+ font-size: 13px;
68
+ font-weight: 500;
69
+ z-index: 1000;
70
+ box-shadow: var(--shadow-sm);
71
+ transition: all 0.2s ease;
72
+ }
73
+
74
+ .dashboard-nav-link:hover {
75
+ background: var(--bg-hover);
76
+ border-color: var(--accent-blue);
77
+ color: var(--accent-blue);
78
+ }
79
+
80
+ .dashboard-nav-link .icon {
81
+ font-size: 14px;
82
+ }
83
+
84
+ /* ============ 連接狀態指示器(底部固定,僅用於 index.html 中的 #connectionStatus) ============ */
85
+
86
+ #connectionStatus {
87
+ position: fixed;
88
+ bottom: 16px;
89
+ left: 50%;
90
+ transform: translateX(-50%);
91
+ padding: var(--spacing-sm) var(--spacing-md);
92
+ background: var(--bg-secondary);
93
+ border: 1px solid var(--border-color);
94
+ border-radius: var(--radius-md);
95
+ display: flex;
96
+ align-items: center;
97
+ gap: var(--spacing-sm);
98
+ font-size: 12px;
99
+ z-index: 999;
100
+ box-shadow: var(--shadow-md);
101
+ }
102
+
103
+ .version-display {
104
+ color: var(--text-muted);
105
+ font-size: 11px;
106
+ margin-left: 8px;
107
+ padding: 2px 6px;
108
+ background: var(--bg-tertiary);
109
+ border-radius: var(--radius-sm);
110
+ }
111
+
112
+ /* ============ 自動回覆計時器(浮動中下) ============ */
113
+
114
+ .auto-reply-timer-floating {
115
+ display: none;
116
+ position: fixed;
117
+ bottom: 20px;
118
+ left: 50%;
119
+ transform: translateX(-50%);
120
+ padding: var(--spacing-sm) var(--spacing-lg);
121
+ background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
122
+ color: white;
123
+ border-radius: var(--radius-lg);
124
+ font-weight: 600;
125
+ font-size: 14px;
126
+ z-index: 1000;
127
+ box-shadow: 0 4px 16px rgba(255, 152, 0, 0.4);
128
+ cursor: pointer;
129
+ animation: timerPulse 1s ease-in-out infinite;
130
+ }
131
+
132
+ .auto-reply-timer-floating.active {
133
+ display: flex;
134
+ align-items: center;
135
+ gap: var(--spacing-sm);
136
+ }
137
+
138
+ .auto-reply-timer-floating.paused {
139
+ opacity: 0.7;
140
+ background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%);
141
+ box-shadow: 0 4px 16px rgba(158, 158, 158, 0.4);
142
+ animation: none;
143
+ }
144
+
145
+ .auto-reply-timer-floating #auto-reply-seconds {
146
+ font-size: 16px;
147
+ font-weight: 700;
148
+ min-width: 24px;
149
+ text-align: center;
150
+ }
151
+
152
+ /* 舊版本的 auto-reply-timer(保留向後兼容) */
153
+ .auto-reply-timer {
154
+ display: none;
155
+ align-items: center;
156
+ color: #ff9800;
157
+ font-weight: 600;
158
+ font-size: 12px;
159
+ margin-left: 12px;
160
+ animation: timerPulse 1s ease-in-out infinite;
161
+ }
162
+
163
+ .auto-reply-timer.active {
164
+ display: inline-flex;
165
+ }
166
+
167
+ /* 暫停狀態視覺化 */
168
+ .auto-reply-timer.paused {
169
+ opacity: 0.6;
170
+ color: #bbbbbb;
171
+ animation: none; /* 停止脈動動畫 */
172
+ }
173
+
174
+ .status-dot {
175
+ width: 8px;
176
+ height: 8px;
177
+ border-radius: 50%;
178
+ background: var(--text-muted);
179
+ animation: pulse 2s ease-in-out infinite;
180
+ }
181
+
182
+ .connection-status.connected .status-dot {
183
+ background: var(--accent-green);
184
+ }
185
+
186
+ .connection-status.disconnected .status-dot {
187
+ background: var(--accent-red);
188
+ animation: none;
189
+ }
190
+
191
+ @keyframes pulse {
192
+
193
+ 0%,
194
+ 100% {
195
+ opacity: 1;
196
+ }
197
+
198
+ 50% {
199
+ opacity: 0.5;
200
+ }
201
+ }
202
+
203
+ /* ============ 三欄式佈局 ============ */
204
+
205
+ .feedback-container {
206
+ display: grid;
207
+ grid-template-columns: 30% 40% 30%;
208
+ gap: var(--spacing-md);
209
+ height: calc(100vh - 60px); /* 扣除導覽列高度 */
210
+ padding: var(--spacing-md);
211
+ }
212
+
213
+ /* 響應式設計 */
214
+ @media (max-width: 768px) {
215
+ .feedback-container {
216
+ grid-template-columns: 1fr;
217
+ grid-template-rows: auto auto auto;
218
+ overflow-y: auto;
219
+ height: auto;
220
+ min-height: calc(100vh - 60px); /* 扣除導覽列高度 */
221
+ }
222
+ }
223
+
224
+ /* ============ 面板通用樣式 ============ */
225
+
226
+ .panel {
227
+ background: var(--bg-secondary);
228
+ border: 1px solid var(--border-color);
229
+ border-radius: var(--radius-md);
230
+ display: flex;
231
+ flex-direction: column;
232
+ overflow: hidden;
233
+ }
234
+
235
+ .panel-header {
236
+ padding: var(--spacing-md);
237
+ border-bottom: 1px solid var(--border-color);
238
+ display: flex;
239
+ align-items: center;
240
+ justify-content: space-between;
241
+ flex-shrink: 0;
242
+ }
243
+
244
+ .panel-title {
245
+ font-size: 14px;
246
+ font-weight: 600;
247
+ color: var(--text-primary);
248
+ display: flex;
249
+ align-items: center;
250
+ gap: var(--spacing-sm);
251
+ }
252
+
253
+ .project-info {
254
+ font-size: 12px;
255
+ color: var(--text-secondary);
256
+ display: flex;
257
+ align-items: center;
258
+ gap: var(--spacing-xs);
259
+ max-width: 200px;
260
+ overflow: hidden;
261
+ text-overflow: ellipsis;
262
+ white-space: nowrap;
263
+ cursor: default;
264
+ }
265
+
266
+ .project-info:hover {
267
+ color: var(--text-primary);
268
+ }
269
+
270
+ .panel-content {
271
+ flex: 1;
272
+ overflow-y: auto;
273
+ overflow-x: hidden;
274
+ }
275
+
276
+ .panel-footer {
277
+ padding: var(--spacing-md);
278
+ border-top: 1px solid var(--border-color);
279
+ flex-shrink: 0;
280
+ }
281
+
282
+ /* ============ 左側:AI 訊息顯示區 ============ */
283
+
284
+ .ai-panel .panel-content {
285
+ padding: var(--spacing-md);
286
+ }
287
+
288
+ .ai-message-display {
289
+ min-height: 200px;
290
+ }
291
+
292
+ .ai-message-display .placeholder {
293
+ display: flex;
294
+ flex-direction: column;
295
+ align-items: center;
296
+ justify-content: center;
297
+ height: 100%;
298
+ min-height: 300px;
299
+ color: var(--text-muted);
300
+ }
301
+
302
+ .ai-message-display .placeholder .icon {
303
+ font-size: 48px;
304
+ margin-bottom: var(--spacing-md);
305
+ }
306
+
307
+ .ai-message-content {
308
+ font-size: 13px;
309
+ line-height: 1.6;
310
+ color: var(--text-primary);
311
+ }
312
+
313
+ .ai-message-content h1,
314
+ .ai-message-content h2,
315
+ .ai-message-content h3 {
316
+ margin-top: var(--spacing-lg);
317
+ margin-bottom: var(--spacing-md);
318
+ color: var(--accent-blue);
319
+ }
320
+
321
+ .ai-message-content p {
322
+ margin-bottom: var(--spacing-md);
323
+ }
324
+
325
+ .ai-message-content code {
326
+ background: var(--bg-tertiary);
327
+ padding: 2px 6px;
328
+ border-radius: var(--radius-sm);
329
+ font-family: "Consolas", "Courier New", monospace;
330
+ font-size: 12px;
331
+ }
332
+
333
+ .ai-message-content pre {
334
+ background: var(--bg-tertiary);
335
+ padding: var(--spacing-md);
336
+ border-radius: var(--radius-sm);
337
+ overflow-x: auto;
338
+ margin-bottom: var(--spacing-md);
339
+ }
340
+
341
+ .ai-message-content ul,
342
+ .ai-message-content ol {
343
+ margin-left: var(--spacing-lg);
344
+ margin-bottom: var(--spacing-md);
345
+ }
346
+
347
+ /* AI 工作匯報區塊連結樣式 */
348
+ .ai-message-content a {
349
+ color: var(--accent-yellow);
350
+ text-decoration: underline;
351
+ transition: color 0.2s ease;
352
+ }
353
+
354
+ .ai-message-content a:hover {
355
+ color: #ffeb3b;
356
+ }
357
+
358
+ /* 淺色模式下使用預設連結顏色 */
359
+ @media (prefers-color-scheme: light) {
360
+ .ai-message-content a {
361
+ color: var(--accent-blue);
362
+ }
363
+
364
+ .ai-message-content a:hover {
365
+ color: #005a9e;
366
+ }
367
+ }
368
+
369
+ /* ============ 中間:使用者互動區 ============ */
370
+
371
+ .user-panel {
372
+ display: grid;
373
+ grid-template-rows: 60% 40%;
374
+ gap: var(--spacing-md);
375
+ }
376
+
377
+ /* 文字輸入區 */
378
+ .input-section {
379
+ display: flex;
380
+ flex-direction: column;
381
+ background: var(--bg-secondary);
382
+ border: 1px solid var(--border-color);
383
+ border-radius: var(--radius-md);
384
+ overflow: hidden;
385
+ }
386
+
387
+ .feedback-input {
388
+ width: 100%;
389
+ height: 88%;
390
+ padding: var(--spacing-md);
391
+ background: var(--bg-tertiary);
392
+ color: var(--text-primary);
393
+ border: none;
394
+ resize: none;
395
+ font-family: inherit;
396
+ font-size: 13px;
397
+ line-height: 1.6;
398
+ }
399
+
400
+ .feedback-input:focus {
401
+ outline: none;
402
+ background: var(--bg-primary);
403
+ }
404
+
405
+ .feedback-input::placeholder {
406
+ color: var(--text-muted);
407
+ }
408
+
409
+ .input-footer {
410
+ padding: var(--spacing-md);
411
+ border-top: 1px solid var(--border-color);
412
+ display: flex;
413
+ align-items: center;
414
+ justify-content: space-between;
415
+ background: var(--bg-secondary);
416
+ }
417
+
418
+ .char-count {
419
+ font-size: 11px;
420
+ color: var(--text-secondary);
421
+ }
422
+
423
+ .input-actions {
424
+ display: flex;
425
+ gap: var(--spacing-sm);
426
+ }
427
+
428
+ /* 自動回覆倒數計時器(在 AI 回覆按鈕左邊) */
429
+ .close-cd {
430
+ display: inline-flex;
431
+ align-items: center;
432
+ justify-content: center;
433
+ padding: var(--spacing-sm) var(--spacing-md);
434
+ background: linear-gradient(135deg, #ff5555 0%, #ff3333 100%);
435
+ color: #ffffff;
436
+ border-radius: var(--radius-md);
437
+ font-size: 18px;
438
+ font-weight: 700;
439
+ min-width: 45px;
440
+ height: 35px;
441
+ animation: closeCountdownPulse 0.5s ease-in-out infinite;
442
+ box-shadow: 0 2px 8px rgba(255, 85, 85, 0.4);
443
+ }
444
+
445
+ @keyframes closeCountdownPulse {
446
+ 0%, 100% {
447
+ transform: scale(1);
448
+ opacity: 1;
449
+ }
450
+ 50% {
451
+ transform: scale(1.1);
452
+ opacity: 0.9;
453
+ }
454
+ }
455
+
456
+ @keyframes timerRotate {
457
+ 0% {
458
+ transform: rotate(0deg);
459
+ }
460
+ 100% {
461
+ transform: rotate(360deg);
462
+ }
463
+ }
464
+
465
+ /* 圖片區 */
466
+ .image-section {
467
+ display: flex;
468
+ flex-direction: column;
469
+ background: var(--bg-secondary);
470
+ border: 1px solid var(--border-color);
471
+ border-radius: var(--radius-md);
472
+ overflow: hidden;
473
+ }
474
+
475
+ .image-drop-zone {
476
+ flex: 1;
477
+ padding: var(--spacing-md);
478
+ border: 2px dashed var(--border-color);
479
+ border-radius: var(--radius-sm);
480
+ margin: var(--spacing-md);
481
+ display: flex;
482
+ align-items: center;
483
+ justify-content: center;
484
+ cursor: pointer;
485
+ transition: all 0.2s ease;
486
+ height: 80%;
487
+ }
488
+
489
+ .image-drop-zone:hover {
490
+ border-color: var(--accent-blue);
491
+ background: var(--bg-tertiary);
492
+ }
493
+
494
+ .image-drop-zone.drag-over {
495
+ border-color: var(--accent-green);
496
+ background: rgba(78, 201, 176, 0.1);
497
+ }
498
+
499
+ .drop-zone-content {
500
+ text-align: center;
501
+ color: var(--text-muted);
502
+ }
503
+
504
+ .drop-zone-content .icon {
505
+ font-size: 36px;
506
+ margin-bottom: var(--spacing-sm);
507
+ display: block;
508
+ }
509
+
510
+ .drop-zone-content .hint {
511
+ font-size: 11px;
512
+ margin-top: var(--spacing-xs);
513
+ }
514
+
515
+ .image-preview-container {
516
+ display: flex;
517
+ flex-wrap: wrap;
518
+ gap: var(--spacing-sm);
519
+ padding: var(--spacing-md);
520
+ max-height: 150px;
521
+ overflow-y: auto;
522
+ }
523
+
524
+ .image-preview {
525
+ position: relative;
526
+ width: 80px;
527
+ height: 80px;
528
+ border-radius: var(--radius-sm);
529
+ overflow: hidden;
530
+ border: 1px solid var(--border-color);
531
+ }
532
+
533
+ .image-preview img {
534
+ width: 100%;
535
+ height: 100%;
536
+ object-fit: cover;
537
+ }
538
+
539
+ .image-preview-remove {
540
+ position: absolute;
541
+ top: 4px;
542
+ right: 4px;
543
+ width: 20px;
544
+ height: 20px;
545
+ background: var(--accent-red);
546
+ border: none;
547
+ border-radius: 50%;
548
+ color: white;
549
+ font-size: 12px;
550
+ cursor: pointer;
551
+ display: flex;
552
+ align-items: center;
553
+ justify-content: center;
554
+ opacity: 0.9;
555
+ transition: opacity 0.2s ease;
556
+ }
557
+
558
+ .image-preview-remove:hover {
559
+ opacity: 1;
560
+ }
561
+
562
+ /* ============ 右側:提示詞管理區 ============ */
563
+
564
+ .prompt-panel .panel-content {
565
+ display: flex;
566
+ flex-direction: column;
567
+ padding: 0;
568
+ }
569
+
570
+ .search-box {
571
+ padding: var(--spacing-md);
572
+ border-bottom: 1px solid var(--border-color);
573
+ flex-shrink: 0;
574
+ }
575
+
576
+ .search-input {
577
+ width: 100%;
578
+ padding: var(--spacing-sm) var(--spacing-md);
579
+ background: var(--bg-tertiary);
580
+ color: var(--text-primary);
581
+ border: 1px solid var(--border-color);
582
+ border-radius: var(--radius-sm);
583
+ font-size: 12px;
584
+ }
585
+
586
+ .search-input:focus {
587
+ outline: none;
588
+ border-color: var(--accent-blue);
589
+ }
590
+
591
+ .prompt-list {
592
+ flex: 1;
593
+ overflow-y: auto;
594
+ padding: var(--spacing-sm);
595
+ }
596
+
597
+ .prompt-list .placeholder {
598
+ display: flex;
599
+ flex-direction: column;
600
+ align-items: center;
601
+ justify-content: center;
602
+ height: 100%;
603
+ min-height: 200px;
604
+ color: var(--text-muted);
605
+ text-align: center;
606
+ }
607
+
608
+ .prompt-list .placeholder .icon {
609
+ font-size: 36px;
610
+ margin-bottom: var(--spacing-md);
611
+ }
612
+
613
+ .prompt-item {
614
+ background: var(--bg-tertiary);
615
+ border: 1px solid var(--border-color);
616
+ border-radius: var(--radius-sm);
617
+ padding: var(--spacing-md);
618
+ margin-bottom: var(--spacing-sm);
619
+ cursor: pointer;
620
+ transition: all 0.2s ease;
621
+ }
622
+
623
+ .prompt-item:hover {
624
+ background: var(--bg-hover);
625
+ border-color: var(--accent-blue);
626
+ }
627
+
628
+ .prompt-item.pinned {
629
+ border-left: 3px solid var(--accent-orange);
630
+ }
631
+
632
+ .prompt-item-header {
633
+ display: flex;
634
+ align-items: center;
635
+ justify-content: space-between;
636
+ margin-bottom: var(--spacing-sm);
637
+ }
638
+
639
+ .prompt-item-title {
640
+ font-weight: 600;
641
+ font-size: 13px;
642
+ color: var(--text-primary);
643
+ flex: 1;
644
+ }
645
+
646
+ .prompt-item-actions {
647
+ display: flex;
648
+ gap: var(--spacing-xs);
649
+ opacity: 0;
650
+ transition: opacity 0.2s ease;
651
+ }
652
+
653
+ .prompt-item:hover .prompt-item-actions {
654
+ opacity: 1;
655
+ }
656
+
657
+ .prompt-item-content {
658
+ font-size: 12px;
659
+ color: var(--text-secondary);
660
+ line-height: 1.4;
661
+ max-height: 60px;
662
+ overflow: hidden;
663
+ text-overflow: ellipsis;
664
+ display: -webkit-box;
665
+ -webkit-line-clamp: 3;
666
+ -webkit-box-orient: vertical;
667
+ }
668
+
669
+ .prompt-item-footer {
670
+ margin-top: var(--spacing-sm);
671
+ display: flex;
672
+ align-items: center;
673
+ gap: var(--spacing-sm);
674
+ }
675
+
676
+ .prompt-item-category {
677
+ font-size: 11px;
678
+ padding: 2px 6px;
679
+ background: var(--bg-primary);
680
+ border-radius: var(--radius-sm);
681
+ color: var(--text-secondary);
682
+ }
683
+
684
+ /* ============ 按鈕樣式 ============ */
685
+
686
+ .btn {
687
+ padding: var(--spacing-sm) var(--spacing-md);
688
+ border: none;
689
+ border-radius: var(--radius-sm);
690
+ font-size: 12px;
691
+ font-weight: 500;
692
+ cursor: pointer;
693
+ display: inline-flex;
694
+ align-items: center;
695
+ gap: var(--spacing-xs);
696
+ transition: all 0.2s ease;
697
+ }
698
+
699
+ .btn:disabled {
700
+ opacity: 0.5;
701
+ cursor: not-allowed;
702
+ }
703
+
704
+ .btn-primary {
705
+ background: var(--accent-blue);
706
+ color: white;
707
+ }
708
+
709
+ .btn-primary:hover:not(:disabled) {
710
+ background: #006bb3;
711
+ }
712
+
713
+ .btn-secondary {
714
+ background: var(--bg-tertiary);
715
+ color: var(--text-primary);
716
+ border: 1px solid var(--border-color);
717
+ }
718
+
719
+ .btn-secondary:hover:not(:disabled) {
720
+ background: var(--bg-hover);
721
+ }
722
+
723
+ .btn-ghost {
724
+ background: transparent;
725
+ color: var(--text-secondary);
726
+ }
727
+
728
+ .btn-ghost:hover:not(:disabled) {
729
+ background: var(--bg-hover);
730
+ color: var(--text-primary);
731
+ }
732
+
733
+ /* Icon 按鈕樣式 - 更明顯的功能按鈕 */
734
+ .btn-icon {
735
+ display: flex;
736
+ flex-direction: column;
737
+ align-items: center;
738
+ justify-content: center;
739
+ padding: 6px 10px;
740
+ min-width: 50px;
741
+ background: var(--bg-tertiary);
742
+ border: 1px solid var(--border-color);
743
+ border-radius: var(--radius-md);
744
+ color: var(--text-secondary);
745
+ transition: all 0.2s ease;
746
+ }
747
+
748
+ .btn-icon:hover:not(:disabled) {
749
+ background: var(--bg-hover);
750
+ border-color: var(--accent-blue);
751
+ color: var(--text-primary);
752
+ transform: translateY(-1px);
753
+ }
754
+
755
+ .btn-icon .icon {
756
+ font-size: 18px;
757
+ margin-bottom: 2px;
758
+ }
759
+
760
+ .btn-icon .btn-label {
761
+ font-size: 9px;
762
+ font-weight: 500;
763
+ text-transform: uppercase;
764
+ letter-spacing: 0.5px;
765
+ }
766
+
767
+ /* 高亮按鈕 - MCP Server 等重要功能 */
768
+ .btn-icon.btn-highlight {
769
+ background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%);
770
+ border-color: transparent;
771
+ color: white;
772
+ }
773
+
774
+ .btn-icon.btn-highlight:hover:not(:disabled) {
775
+ background: linear-gradient(135deg, #7c3aed 0%, #0066cc 100%);
776
+ transform: translateY(-2px);
777
+ box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
778
+ }
779
+
780
+ .btn-icon.btn-highlight .btn-label {
781
+ color: white;
782
+ }
783
+
784
+ /* Header actions 容器 */
785
+ .header-actions {
786
+ display: flex;
787
+ gap: var(--spacing-xs);
788
+ align-items: center;
789
+ }
790
+
791
+ .btn-sm {
792
+ padding: 4px 8px;
793
+ font-size: 11px;
794
+ }
795
+
796
+ .btn-block {
797
+ width: 100%;
798
+ justify-content: center;
799
+ }
800
+
801
+ .icon {
802
+ font-style: normal;
803
+ }
804
+
805
+ .badge {
806
+ display: inline-block;
807
+ padding: 2px 6px;
808
+ background: var(--accent-blue);
809
+ color: white;
810
+ border-radius: var(--radius-sm);
811
+ font-size: 10px;
812
+ font-weight: 600;
813
+ }
814
+
815
+ /* ============ 彈窗樣式 ============ */
816
+
817
+ .modal {
818
+ display: none;
819
+ position: fixed;
820
+ top: 0;
821
+ left: 0;
822
+ width: 100%;
823
+ height: 100%;
824
+ z-index: 2000;
825
+ }
826
+
827
+ .modal.show {
828
+ display: flex;
829
+ align-items: center;
830
+ justify-content: center;
831
+ }
832
+
833
+ .modal-overlay {
834
+ position: absolute;
835
+ top: 0;
836
+ left: 0;
837
+ width: 100%;
838
+ height: 100%;
839
+ background: rgba(0, 0, 0, 0.7);
840
+ }
841
+
842
+ .modal-content {
843
+ position: relative;
844
+ background: var(--bg-secondary);
845
+ border: 1px solid var(--border-color);
846
+ border-radius: var(--radius-md);
847
+ max-width: 600px;
848
+ width: 90%;
849
+ max-height: 90vh;
850
+ display: flex;
851
+ flex-direction: column;
852
+ box-shadow: var(--shadow-lg);
853
+ animation: modalSlideIn 0.3s ease;
854
+ }
855
+
856
+ .modal-sm .modal-content {
857
+ max-width: 500px;
858
+ }
859
+
860
+ @keyframes modalSlideIn {
861
+ from {
862
+ opacity: 0;
863
+ transform: translateY(-20px);
864
+ }
865
+
866
+ to {
867
+ opacity: 1;
868
+ transform: translateY(0);
869
+ }
870
+ }
871
+
872
+ .modal-header {
873
+ padding: var(--spacing-lg);
874
+ border-bottom: 1px solid var(--border-color);
875
+ display: flex;
876
+ align-items: center;
877
+ justify-content: space-between;
878
+ }
879
+
880
+ .modal-title {
881
+ font-size: 16px;
882
+ font-weight: 600;
883
+ display: flex;
884
+ align-items: center;
885
+ gap: var(--spacing-sm);
886
+ }
887
+
888
+ .modal-close {
889
+ background: transparent;
890
+ border: none;
891
+ color: var(--text-secondary);
892
+ font-size: 16px;
893
+ cursor: pointer;
894
+ padding: var(--spacing-xs);
895
+ border-radius: var(--radius-sm);
896
+ transition: all 0.2s ease;
897
+ }
898
+
899
+ .modal-close:hover {
900
+ background: var(--bg-hover);
901
+ color: var(--text-primary);
902
+ }
903
+
904
+ .modal-body {
905
+ padding: var(--spacing-lg);
906
+ overflow-y: auto;
907
+ flex: 1;
908
+ }
909
+
910
+ .modal-footer {
911
+ padding: var(--spacing-lg);
912
+ border-top: 1px solid var(--border-color);
913
+ display: flex;
914
+ gap: var(--spacing-sm);
915
+ justify-content: flex-end;
916
+ }
917
+
918
+ /* ============ 表單樣式 ============ */
919
+
920
+ .form-group {
921
+ margin-bottom: var(--spacing-md);
922
+ }
923
+
924
+ .form-group label {
925
+ display: block;
926
+ margin-bottom: var(--spacing-xs);
927
+ font-size: 12px;
928
+ font-weight: 500;
929
+ color: var(--text-secondary);
930
+ }
931
+
932
+ .form-control {
933
+ width: 100%;
934
+ padding: var(--spacing-sm) var(--spacing-md);
935
+ background: var(--bg-tertiary);
936
+ color: var(--text-primary);
937
+ border: 1px solid var(--border-color);
938
+ border-radius: var(--radius-sm);
939
+ font-size: 13px;
940
+ font-family: inherit;
941
+ }
942
+
943
+ .form-control:focus {
944
+ outline: none;
945
+ border-color: var(--accent-blue);
946
+ }
947
+
948
+ .form-control::placeholder {
949
+ color: var(--text-muted);
950
+ }
951
+
952
+ textarea.form-control {
953
+ resize: vertical;
954
+ line-height: 1.5;
955
+ }
956
+
957
+ .form-hint {
958
+ display: block;
959
+ margin-top: var(--spacing-xs);
960
+ font-size: 11px;
961
+ color: var(--text-muted);
962
+ }
963
+
964
+ .form-row {
965
+ display: grid;
966
+ grid-template-columns: 1fr 1fr;
967
+ gap: var(--spacing-md);
968
+ }
969
+
970
+ .input-group {
971
+ display: flex;
972
+ gap: var(--spacing-xs);
973
+ }
974
+
975
+ .input-group .form-control {
976
+ flex: 1;
977
+ }
978
+
979
+ .form-check {
980
+ display: flex;
981
+ align-items: center;
982
+ gap: var(--spacing-sm);
983
+ margin-bottom: var(--spacing-md);
984
+ }
985
+
986
+ .form-check-input {
987
+ width: 16px;
988
+ height: 16px;
989
+ cursor: pointer;
990
+ }
991
+
992
+ .form-check-label {
993
+ font-size: 13px;
994
+ cursor: pointer;
995
+ display: flex;
996
+ align-items: center;
997
+ gap: var(--spacing-xs);
998
+ }
999
+
1000
+ .checkbox-label {
1001
+ display: flex;
1002
+ align-items: center;
1003
+ gap: var(--spacing-sm);
1004
+ cursor: pointer;
1005
+ font-size: 13px;
1006
+ margin-top: var(--spacing-sm);
1007
+ }
1008
+
1009
+ .checkbox-label input[type="checkbox"] {
1010
+ width: 18px;
1011
+ height: 18px;
1012
+ cursor: pointer;
1013
+ accent-color: var(--accent-primary);
1014
+ }
1015
+
1016
+ .checkbox-text {
1017
+ color: var(--text-primary);
1018
+ }
1019
+
1020
+ /* ============ 自動回覆計時器(底部固定) ============ */
1021
+
1022
+ .auto-reply-timer-bottom {
1023
+ position: fixed;
1024
+ bottom: var(--spacing-lg);
1025
+ left: 50%;
1026
+ transform: translateX(-50%);
1027
+ display: flex;
1028
+ align-items: center;
1029
+ gap: 6px;
1030
+ padding: 6px 12px;
1031
+ border-radius: 20px;
1032
+ background: #fff3e0;
1033
+ font-size: 13px;
1034
+ font-weight: 500;
1035
+ box-shadow: var(--shadow-md);
1036
+ z-index: 1500;
1037
+ cursor: pointer;
1038
+ transition: all 0.3s ease;
1039
+ animation: slideUpBottom 0.3s ease, timerPulseBottom 1s ease-in-out infinite;
1040
+ }
1041
+
1042
+ .auto-reply-timer-bottom:hover {
1043
+ background: #ffe0b2;
1044
+ box-shadow: var(--shadow-lg);
1045
+ }
1046
+
1047
+ .auto-reply-timer-bottom.paused {
1048
+ background: #f5f5f5;
1049
+ animation: slideUpBottom 0.3s ease;
1050
+ }
1051
+
1052
+ .auto-reply-timer-bottom.paused .status-dot {
1053
+ background: #9e9e9e;
1054
+ box-shadow: none;
1055
+ animation: none;
1056
+ }
1057
+
1058
+ .auto-reply-timer-bottom.paused .status-text,
1059
+ .auto-reply-timer-bottom.paused .timer-value,
1060
+ .auto-reply-timer-bottom.paused .timer-unit {
1061
+ color: #9e9e9e;
1062
+ }
1063
+
1064
+ .auto-reply-timer-bottom .status-dot {
1065
+ width: 8px;
1066
+ height: 8px;
1067
+ border-radius: 50%;
1068
+ background: #ff9800;
1069
+ box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2);
1070
+ animation: dotPulse 1s ease-in-out infinite;
1071
+ }
1072
+
1073
+ .auto-reply-timer-bottom .status-text {
1074
+ color: #e65100;
1075
+ }
1076
+
1077
+ .auto-reply-timer-bottom .timer-value {
1078
+ color: #e65100;
1079
+ font-weight: 700;
1080
+ min-width: 24px;
1081
+ text-align: center;
1082
+ }
1083
+
1084
+ .auto-reply-timer-bottom .timer-unit {
1085
+ color: #f57c00;
1086
+ }
1087
+
1088
+ @keyframes slideUpBottom {
1089
+ from {
1090
+ opacity: 0;
1091
+ transform: translateX(-50%) translateY(100%);
1092
+ }
1093
+ to {
1094
+ opacity: 1;
1095
+ transform: translateX(-50%) translateY(0);
1096
+ }
1097
+ }
1098
+
1099
+ @keyframes timerPulseBottom {
1100
+ 0%, 100% {
1101
+ opacity: 1;
1102
+ }
1103
+ 50% {
1104
+ opacity: 0.85;
1105
+ }
1106
+ }
1107
+
1108
+ @keyframes dotPulse {
1109
+ 0%, 100% {
1110
+ transform: scale(1);
1111
+ }
1112
+ 50% {
1113
+ transform: scale(1.1);
1114
+ }
1115
+ }
1116
+
1117
+ /* ============ Toast 通知 ============ */
1118
+
1119
+ .toast-container {
1120
+ position: fixed;
1121
+ bottom: var(--spacing-lg);
1122
+ right: var(--spacing-lg);
1123
+ z-index: 3000;
1124
+ display: flex;
1125
+ flex-direction: column;
1126
+ gap: var(--spacing-sm);
1127
+ max-width: 400px;
1128
+ }
1129
+
1130
+ .toast {
1131
+ background: var(--bg-secondary);
1132
+ border: 1px solid var(--border-color);
1133
+ border-radius: var(--radius-md);
1134
+ padding: var(--spacing-md);
1135
+ box-shadow: var(--shadow-lg);
1136
+ display: flex;
1137
+ align-items: flex-start;
1138
+ gap: var(--spacing-md);
1139
+ animation: toastSlideIn 0.3s ease;
1140
+ }
1141
+
1142
+ @keyframes toastSlideIn {
1143
+ from {
1144
+ opacity: 0;
1145
+ transform: translateY(20px);
1146
+ }
1147
+
1148
+ to {
1149
+ opacity: 1;
1150
+ transform: translateY(0);
1151
+ }
1152
+ }
1153
+
1154
+ .toast.success {
1155
+ border-left: 4px solid var(--accent-green);
1156
+ }
1157
+
1158
+ .toast.error {
1159
+ border-left: 4px solid var(--accent-red);
1160
+ }
1161
+
1162
+ .toast.info {
1163
+ border-left: 4px solid var(--accent-blue);
1164
+ }
1165
+
1166
+ .toast-icon {
1167
+ font-size: 20px;
1168
+ flex-shrink: 0;
1169
+ }
1170
+
1171
+ .toast-content {
1172
+ flex: 1;
1173
+ }
1174
+
1175
+ .toast-title {
1176
+ font-weight: 600;
1177
+ margin-bottom: var(--spacing-xs);
1178
+ }
1179
+
1180
+ .toast-message {
1181
+ font-size: 12px;
1182
+ color: var(--text-secondary);
1183
+ }
1184
+
1185
+ /* ============ 載入中覆蓋層 ============ */
1186
+
1187
+ .loading-overlay {
1188
+ position: fixed;
1189
+ top: 0;
1190
+ left: 0;
1191
+ width: 100%;
1192
+ height: 100%;
1193
+ background: rgba(30, 30, 30, 0.9);
1194
+ z-index: 4000;
1195
+ display: flex;
1196
+ align-items: center;
1197
+ justify-content: center;
1198
+ }
1199
+
1200
+ .loading-spinner {
1201
+ text-align: center;
1202
+ }
1203
+
1204
+ .spinner {
1205
+ width: 40px;
1206
+ height: 40px;
1207
+ margin: 0 auto var(--spacing-md);
1208
+ border: 4px solid var(--border-color);
1209
+ border-top-color: var(--accent-blue);
1210
+ border-radius: 50%;
1211
+ animation: spin 1s linear infinite;
1212
+ }
1213
+
1214
+ @keyframes spin {
1215
+ to {
1216
+ transform: rotate(360deg);
1217
+ }
1218
+ }
1219
+
1220
+ #loadingText {
1221
+ color: var(--text-primary);
1222
+ font-size: 14px;
1223
+ }
1224
+
1225
+ /* ============ AI 工具執行進度 ============ */
1226
+
1227
+ .ai-tool-progress {
1228
+ margin-top: var(--spacing-md);
1229
+ padding: var(--spacing-md);
1230
+ background: var(--bg-tertiary);
1231
+ border-radius: var(--radius-md);
1232
+ border: 1px solid var(--border-color);
1233
+ text-align: center;
1234
+ }
1235
+
1236
+ .progress-round {
1237
+ color: var(--accent-blue);
1238
+ font-weight: 600;
1239
+ font-size: 12px;
1240
+ margin-bottom: var(--spacing-xs);
1241
+ }
1242
+
1243
+ .progress-status {
1244
+ color: var(--text-primary);
1245
+ font-size: 13px;
1246
+ margin-bottom: var(--spacing-sm);
1247
+ }
1248
+
1249
+ .tool-list {
1250
+ display: flex;
1251
+ flex-wrap: wrap;
1252
+ gap: var(--spacing-xs);
1253
+ justify-content: center;
1254
+ }
1255
+
1256
+ .tool-tag {
1257
+ display: inline-block;
1258
+ background: var(--accent-blue);
1259
+ color: white;
1260
+ padding: 2px 8px;
1261
+ border-radius: var(--radius-sm);
1262
+ font-size: 11px;
1263
+ font-family: monospace;
1264
+ }
1265
+
1266
+ /* ============ 滾動條樣式 ============ */
1267
+
1268
+ ::-webkit-scrollbar {
1269
+ width: 10px;
1270
+ height: 10px;
1271
+ }
1272
+
1273
+ ::-webkit-scrollbar-track {
1274
+ background: var(--bg-secondary);
1275
+ }
1276
+
1277
+ ::-webkit-scrollbar-thumb {
1278
+ background: var(--bg-hover);
1279
+ border-radius: var(--radius-sm);
1280
+ }
1281
+
1282
+ ::-webkit-scrollbar-thumb:hover {
1283
+ background: var(--border-color);
1284
+ }
1285
+
1286
+ /* ============ 工具提示樣式 ============ */
1287
+
1288
+ [title] {
1289
+ position: relative;
1290
+ }
1291
+
1292
+ /* ============ 輔助類別 ============ */
1293
+
1294
+ .text-center {
1295
+ text-align: center;
1296
+ }
1297
+
1298
+ .text-muted {
1299
+ color: var(--text-muted);
1300
+ }
1301
+
1302
+ .mb-0 {
1303
+ margin-bottom: 0;
1304
+ }
1305
+
1306
+ .mb-1 {
1307
+ margin-bottom: var(--spacing-xs);
1308
+ }
1309
+
1310
+ .mb-2 {
1311
+ margin-bottom: var(--spacing-sm);
1312
+ }
1313
+
1314
+ .mb-3 {
1315
+ margin-bottom: var(--spacing-md);
1316
+ }
1317
+
1318
+ .mb-4 {
1319
+ margin-bottom: var(--spacing-lg);
1320
+ }
1321
+
1322
+ .mt-0 {
1323
+ margin-top: 0;
1324
+ }
1325
+
1326
+ .mt-1 {
1327
+ margin-top: var(--spacing-xs);
1328
+ }
1329
+
1330
+ .mt-2 {
1331
+ margin-top: var(--spacing-sm);
1332
+ }
1333
+
1334
+ .mt-3 {
1335
+ margin-top: var(--spacing-md);
1336
+ }
1337
+
1338
+ .mt-4 {
1339
+ margin-top: var(--spacing-lg);
1340
+ }
1341
+
1342
+ /* ============ 日誌檢視器樣式 ============ */
1343
+
1344
+ .modal-lg {
1345
+ max-width: 900px;
1346
+ width: 95%;
1347
+ }
1348
+
1349
+ .modal-lg .modal-body {
1350
+ padding: var(--spacing-sm);
1351
+ }
1352
+
1353
+ .log-filter-bar {
1354
+ display: flex;
1355
+ gap: var(--spacing-xs);
1356
+ align-items: center;
1357
+ flex-wrap: wrap;
1358
+ margin-bottom: var(--spacing-sm);
1359
+ padding-bottom: var(--spacing-sm);
1360
+ border-bottom: 1px solid var(--border-color);
1361
+ }
1362
+
1363
+ .log-filter-bar .form-control {
1364
+ height: 28px;
1365
+ padding: 2px 6px;
1366
+ font-size: 12px;
1367
+ }
1368
+
1369
+ .log-filter-bar input[type="text"] {
1370
+ flex: 1;
1371
+ min-width: 150px;
1372
+ }
1373
+
1374
+ .log-select-sm {
1375
+ width: 90px !important;
1376
+ flex: 0 0 auto !important;
1377
+ }
1378
+
1379
+ .log-date-sm {
1380
+ width: 110px !important;
1381
+ flex: 0 0 auto !important;
1382
+ }
1383
+
1384
+ .log-filter-bar .btn {
1385
+ height: 28px;
1386
+ padding: 2px 8px;
1387
+ font-size: 12px;
1388
+ }
1389
+
1390
+ .log-entries-container {
1391
+ max-height: 350px;
1392
+ overflow-y: auto;
1393
+ background: var(--bg-primary);
1394
+ border: 1px solid var(--border-color);
1395
+ border-radius: var(--radius-sm);
1396
+ margin-bottom: var(--spacing-xs);
1397
+ }
1398
+
1399
+ .log-entry {
1400
+ display: flex;
1401
+ flex-direction: column;
1402
+ padding: 4px 8px;
1403
+ border-bottom: 1px solid var(--border-color);
1404
+ font-family: "Cascadia Code", "Fira Code", "Consolas", monospace;
1405
+ font-size: 11px;
1406
+ line-height: 1.3;
1407
+ }
1408
+
1409
+ .log-entry:last-child {
1410
+ border-bottom: none;
1411
+ }
1412
+
1413
+ .log-entry:hover {
1414
+ background: var(--bg-hover);
1415
+ }
1416
+
1417
+ .log-entry-header {
1418
+ display: flex;
1419
+ align-items: center;
1420
+ gap: 6px;
1421
+ margin-bottom: 2px;
1422
+ }
1423
+
1424
+ .log-timestamp {
1425
+ color: var(--text-muted);
1426
+ font-size: 10px;
1427
+ flex-shrink: 0;
1428
+ }
1429
+
1430
+ .log-level {
1431
+ padding: 1px 4px;
1432
+ border-radius: 2px;
1433
+ font-size: 9px;
1434
+ font-weight: 600;
1435
+ text-transform: uppercase;
1436
+ flex-shrink: 0;
1437
+ }
1438
+
1439
+ .log-level-error {
1440
+ background: rgba(244, 135, 113, 0.2);
1441
+ color: var(--accent-red);
1442
+ }
1443
+
1444
+ .log-level-warn {
1445
+ background: rgba(206, 145, 120, 0.2);
1446
+ color: var(--accent-orange);
1447
+ }
1448
+
1449
+ .log-level-info {
1450
+ background: rgba(0, 122, 204, 0.2);
1451
+ color: var(--accent-blue);
1452
+ }
1453
+
1454
+ .log-level-debug {
1455
+ background: rgba(78, 201, 176, 0.2);
1456
+ color: var(--accent-green);
1457
+ }
1458
+
1459
+ .log-source {
1460
+ color: var(--accent-yellow);
1461
+ font-size: 10px;
1462
+ flex-shrink: 0;
1463
+ }
1464
+
1465
+ .log-message {
1466
+ color: var(--text-primary);
1467
+ word-break: break-word;
1468
+ white-space: pre-wrap;
1469
+ font-size: 11px;
1470
+ }
1471
+
1472
+ .log-meta {
1473
+ margin-top: 2px;
1474
+ padding: 2px 6px;
1475
+ background: var(--bg-tertiary);
1476
+ border-radius: 2px;
1477
+ font-size: 10px;
1478
+ color: var(--text-secondary);
1479
+ overflow-x: auto;
1480
+ }
1481
+
1482
+ .log-meta pre {
1483
+ margin: 0;
1484
+ font-size: 10px;
1485
+ }
1486
+
1487
+ .log-pagination {
1488
+ display: flex;
1489
+ align-items: center;
1490
+ justify-content: center;
1491
+ gap: var(--spacing-sm);
1492
+ padding: var(--spacing-xs) 0;
1493
+ }
1494
+
1495
+ .log-page-info {
1496
+ color: var(--text-secondary);
1497
+ font-size: 11px;
1498
+ min-width: 50px;
1499
+ text-align: center;
1500
+ }
1501
+
1502
+ /* 日誌條目高亮(搜尋匹配) */
1503
+ .log-entry mark {
1504
+ background: rgba(255, 213, 0, 0.3);
1505
+ color: inherit;
1506
+ padding: 0 2px;
1507
+ border-radius: 2px;
1508
+ }
1509
+
1510
+ /* 日誌載入狀態 */
1511
+ .log-loading {
1512
+ display: flex;
1513
+ align-items: center;
1514
+ justify-content: center;
1515
+ padding: var(--spacing-lg);
1516
+ color: var(--text-secondary);
1517
+ }
1518
+
1519
+ .log-loading .spinner {
1520
+ width: 20px;
1521
+ height: 20px;
1522
+ border: 2px solid var(--border-color);
1523
+ border-top-color: var(--accent-blue);
1524
+ border-radius: 50%;
1525
+ animation: spin 1s linear infinite;
1526
+ margin-right: var(--spacing-sm);
1527
+ }
1528
+
1529
+ /* ============ MCP Servers 樣式 ============ */
1530
+
1531
+ .mcp-server-list {
1532
+ max-height: 400px;
1533
+ overflow-y: auto;
1534
+ }
1535
+
1536
+ .mcp-server-item {
1537
+ display: flex;
1538
+ align-items: center;
1539
+ gap: var(--spacing-sm);
1540
+ padding: var(--spacing-sm) var(--spacing-md);
1541
+ border: 1px solid var(--border-color);
1542
+ border-radius: var(--radius-sm);
1543
+ margin-bottom: var(--spacing-sm);
1544
+ background: var(--bg-secondary);
1545
+ transition: background-color 0.2s;
1546
+ }
1547
+
1548
+ .mcp-server-item:hover {
1549
+ background: var(--bg-hover);
1550
+ }
1551
+
1552
+ .mcp-server-status {
1553
+ width: 10px;
1554
+ height: 10px;
1555
+ border-radius: 50%;
1556
+ flex-shrink: 0;
1557
+ }
1558
+
1559
+ .mcp-server-status.disconnected {
1560
+ background: var(--text-muted);
1561
+ }
1562
+
1563
+ .mcp-server-status.connecting {
1564
+ background: var(--accent-yellow);
1565
+ animation: pulse 1s infinite;
1566
+ }
1567
+
1568
+ .mcp-server-status.connected {
1569
+ background: var(--accent-green);
1570
+ }
1571
+
1572
+ .mcp-server-status.error {
1573
+ background: var(--accent-red);
1574
+ }
1575
+
1576
+ @keyframes pulse {
1577
+ 0%, 100% { opacity: 1; }
1578
+ 50% { opacity: 0.5; }
1579
+ }
1580
+
1581
+ .mcp-server-info {
1582
+ flex: 1;
1583
+ min-width: 0;
1584
+ }
1585
+
1586
+ .mcp-server-name {
1587
+ font-weight: 500;
1588
+ color: var(--text-primary);
1589
+ white-space: nowrap;
1590
+ overflow: hidden;
1591
+ text-overflow: ellipsis;
1592
+ }
1593
+
1594
+ .mcp-server-details {
1595
+ font-size: 11px;
1596
+ color: var(--text-secondary);
1597
+ display: flex;
1598
+ gap: var(--spacing-sm);
1599
+ flex-wrap: wrap;
1600
+ }
1601
+
1602
+ .mcp-server-transport {
1603
+ background: var(--bg-tertiary);
1604
+ padding: 1px 6px;
1605
+ border-radius: var(--radius-sm);
1606
+ }
1607
+
1608
+ .mcp-server-tools-count {
1609
+ color: var(--accent-green);
1610
+ }
1611
+
1612
+ .mcp-server-actions {
1613
+ display: flex;
1614
+ gap: var(--spacing-xs);
1615
+ flex-shrink: 0;
1616
+ }
1617
+
1618
+ .mcp-server-actions .btn {
1619
+ padding: 4px 8px;
1620
+ font-size: 11px;
1621
+ }
1622
+
1623
+ /* MCP Server 連接/編輯按鈕 */
1624
+ .mcp-server-item .btn-connect {
1625
+ color: var(--accent-green);
1626
+ }
1627
+
1628
+ .mcp-server-item .btn-disconnect {
1629
+ color: var(--accent-red);
1630
+ }
1631
+
1632
+ .mcp-server-item .btn-edit {
1633
+ color: var(--accent-blue);
1634
+ }
1635
+
1636
+ .mcp-server-item .btn-delete {
1637
+ color: var(--accent-red);
1638
+ }
1639
+
1640
+ /* 傳輸設定區域 */
1641
+ .transport-settings {
1642
+ margin-top: var(--spacing-sm);
1643
+ padding-top: var(--spacing-sm);
1644
+ border-top: 1px solid var(--border-color);
1645
+ }
1646
+
1647
+ /* Modal 大尺寸 */
1648
+ .modal-lg .modal-content {
1649
+ max-width: 700px;
1650
+ }
1651
+
1652
+ /* MCP 工具列表 (展開時顯示) */
1653
+ .mcp-tools-list {
1654
+ margin-top: var(--spacing-sm);
1655
+ padding: var(--spacing-sm);
1656
+ background: var(--bg-tertiary);
1657
+ border-radius: var(--radius-sm);
1658
+ max-height: 150px;
1659
+ overflow-y: auto;
1660
+ }
1661
+
1662
+ .mcp-tool-item {
1663
+ display: flex;
1664
+ justify-content: space-between;
1665
+ align-items: center;
1666
+ padding: var(--spacing-xs) 0;
1667
+ font-size: 11px;
1668
+ border-bottom: 1px solid var(--border-color);
1669
+ }
1670
+
1671
+ .mcp-tool-item:last-child {
1672
+ border-bottom: none;
1673
+ }
1674
+
1675
+ .mcp-tool-name {
1676
+ font-family: "Consolas", "Monaco", monospace;
1677
+ color: var(--accent-yellow);
1678
+ }
1679
+
1680
+ .mcp-tool-desc {
1681
+ color: var(--text-secondary);
1682
+ font-size: 10px;
1683
+ white-space: nowrap;
1684
+ overflow: hidden;
1685
+ text-overflow: ellipsis;
1686
+ max-width: 300px;
1687
+ }
1688
+
1689
+ /* MCP Server 錯誤訊息 */
1690
+ .mcp-server-error {
1691
+ font-size: 11px;
1692
+ color: var(--accent-red);
1693
+ margin-top: var(--spacing-xs);
1694
+ }
1695
+
1696
+ /* ============ AI Streaming Panel ============ */
1697
+
1698
+ .ai-streaming-panel {
1699
+ position: fixed;
1700
+ top: 0;
1701
+ left: 0;
1702
+ right: 0;
1703
+ bottom: 0;
1704
+ background: rgba(0, 0, 0, 0.85);
1705
+ z-index: 2000;
1706
+ display: flex;
1707
+ align-items: center;
1708
+ justify-content: center;
1709
+ }
1710
+
1711
+ .streaming-content {
1712
+ background: var(--bg-secondary);
1713
+ border: 1px solid var(--border-color);
1714
+ border-radius: var(--radius-lg);
1715
+ width: 90%;
1716
+ max-width: 800px;
1717
+ max-height: 80vh;
1718
+ display: flex;
1719
+ flex-direction: column;
1720
+ box-shadow: var(--shadow-lg);
1721
+ }
1722
+
1723
+ .streaming-header {
1724
+ display: flex;
1725
+ justify-content: space-between;
1726
+ align-items: center;
1727
+ padding: var(--spacing-md) var(--spacing-lg);
1728
+ border-bottom: 1px solid var(--border-color);
1729
+ background: var(--bg-tertiary);
1730
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
1731
+ }
1732
+
1733
+ .streaming-title {
1734
+ display: flex;
1735
+ align-items: center;
1736
+ gap: var(--spacing-sm);
1737
+ font-size: 16px;
1738
+ font-weight: 600;
1739
+ color: var(--text-primary);
1740
+ }
1741
+
1742
+ .streaming-title .icon {
1743
+ font-size: 20px;
1744
+ }
1745
+
1746
+ .streaming-status {
1747
+ display: flex;
1748
+ align-items: center;
1749
+ gap: var(--spacing-sm);
1750
+ font-size: 12px;
1751
+ color: var(--text-secondary);
1752
+ }
1753
+
1754
+ .status-indicator {
1755
+ width: 8px;
1756
+ height: 8px;
1757
+ border-radius: 50%;
1758
+ background: var(--text-muted);
1759
+ }
1760
+
1761
+ .status-indicator.thinking {
1762
+ background: var(--accent-yellow);
1763
+ animation: pulse 1.5s ease-in-out infinite;
1764
+ }
1765
+
1766
+ .status-indicator.executing {
1767
+ background: var(--accent-blue);
1768
+ animation: pulse 1s ease-in-out infinite;
1769
+ }
1770
+
1771
+ .status-indicator.done {
1772
+ background: var(--accent-green);
1773
+ }
1774
+
1775
+ .status-indicator.error {
1776
+ background: var(--accent-red);
1777
+ }
1778
+
1779
+ .streaming-body {
1780
+ flex: 1;
1781
+ overflow-y: auto;
1782
+ padding: var(--spacing-md) var(--spacing-lg);
1783
+ display: flex;
1784
+ flex-direction: column;
1785
+ gap: var(--spacing-md);
1786
+ min-height: 300px;
1787
+ }
1788
+
1789
+ .streaming-progress {
1790
+ display: flex;
1791
+ flex-direction: column;
1792
+ gap: var(--spacing-sm);
1793
+ }
1794
+
1795
+ .progress-item {
1796
+ display: flex;
1797
+ align-items: flex-start;
1798
+ gap: var(--spacing-sm);
1799
+ padding: var(--spacing-sm);
1800
+ background: var(--bg-tertiary);
1801
+ border-radius: var(--radius-sm);
1802
+ font-size: 12px;
1803
+ }
1804
+
1805
+ .progress-item.active {
1806
+ border-left: 3px solid var(--accent-blue);
1807
+ }
1808
+
1809
+ .progress-item.completed {
1810
+ border-left: 3px solid var(--accent-green);
1811
+ opacity: 0.8;
1812
+ }
1813
+
1814
+ .progress-item.error {
1815
+ border-left: 3px solid var(--accent-red);
1816
+ }
1817
+
1818
+ .progress-icon {
1819
+ font-size: 14px;
1820
+ flex-shrink: 0;
1821
+ }
1822
+
1823
+ .progress-content {
1824
+ flex: 1;
1825
+ min-width: 0;
1826
+ }
1827
+
1828
+ .progress-message {
1829
+ color: var(--text-primary);
1830
+ margin-bottom: 2px;
1831
+ }
1832
+
1833
+ .progress-details {
1834
+ color: var(--text-secondary);
1835
+ font-size: 11px;
1836
+ word-break: break-all;
1837
+ }
1838
+
1839
+ .progress-tools {
1840
+ display: flex;
1841
+ flex-wrap: wrap;
1842
+ gap: 4px;
1843
+ margin-top: 4px;
1844
+ }
1845
+
1846
+ .tool-tag {
1847
+ display: inline-block;
1848
+ padding: 2px 8px;
1849
+ background: var(--bg-hover);
1850
+ border: 1px solid var(--border-color);
1851
+ border-radius: 12px;
1852
+ font-size: 10px;
1853
+ font-family: "Consolas", "Monaco", monospace;
1854
+ color: var(--accent-yellow);
1855
+ }
1856
+
1857
+ .streaming-output {
1858
+ flex: 1;
1859
+ padding: var(--spacing-md);
1860
+ background: var(--bg-primary);
1861
+ border: 1px solid var(--border-color);
1862
+ border-radius: var(--radius-sm);
1863
+ overflow-y: auto;
1864
+ font-family: "Consolas", "Monaco", monospace;
1865
+ font-size: 12px;
1866
+ line-height: 1.6;
1867
+ white-space: pre-wrap;
1868
+ color: var(--text-primary);
1869
+ min-height: 150px;
1870
+ }
1871
+
1872
+ .streaming-output .tool-call-display {
1873
+ margin: var(--spacing-sm) 0;
1874
+ padding: 0;
1875
+ background: var(--bg-tertiary);
1876
+ border-radius: var(--radius-sm);
1877
+ border-left: 3px solid var(--accent-blue);
1878
+ }
1879
+
1880
+ .streaming-output .tool-result-display {
1881
+ margin: var(--spacing-sm) 0;
1882
+ padding: 0;
1883
+ background: var(--bg-tertiary);
1884
+ border-radius: var(--radius-sm);
1885
+ border-left: 3px solid var(--accent-green);
1886
+ }
1887
+
1888
+ .streaming-output .ai-message {
1889
+ margin: var(--spacing-sm) 0;
1890
+ padding: 0;
1891
+ background: var(--bg-tertiary);
1892
+ border-radius: var(--radius-sm);
1893
+ border-left: 3px solid var(--accent-yellow);
1894
+ color: var(--text-primary);
1895
+ }
1896
+
1897
+ /* details/summary 可收合樣式 */
1898
+ .streaming-output details {
1899
+ cursor: pointer;
1900
+ }
1901
+
1902
+ .streaming-output details summary {
1903
+ padding: var(--spacing-sm);
1904
+ font-weight: 600;
1905
+ font-size: 12px;
1906
+ user-select: none;
1907
+ list-style: none;
1908
+ display: flex;
1909
+ align-items: center;
1910
+ gap: var(--spacing-xs);
1911
+ }
1912
+
1913
+ .streaming-output details summary::-webkit-details-marker {
1914
+ display: none;
1915
+ }
1916
+
1917
+ .streaming-output details summary::before {
1918
+ content: "▶";
1919
+ font-size: 10px;
1920
+ transition: transform 0.2s ease;
1921
+ color: var(--text-secondary);
1922
+ }
1923
+
1924
+ .streaming-output details[open] summary::before {
1925
+ transform: rotate(90deg);
1926
+ }
1927
+
1928
+ .streaming-output details .details-content {
1929
+ padding: 0 var(--spacing-sm) var(--spacing-sm) var(--spacing-sm);
1930
+ border-top: 1px solid var(--border-color);
1931
+ max-height: 300px;
1932
+ overflow-y: auto;
1933
+ }
1934
+
1935
+ .streaming-output details .details-content pre {
1936
+ margin: 0;
1937
+ white-space: pre-wrap;
1938
+ word-break: break-all;
1939
+ font-size: 11px;
1940
+ line-height: 1.4;
1941
+ }
1942
+
1943
+ .streaming-output .streaming-cursor {
1944
+ display: inline-block;
1945
+ width: 8px;
1946
+ height: 14px;
1947
+ background: var(--accent-blue);
1948
+ animation: blink 1s step-end infinite;
1949
+ }
1950
+
1951
+ @keyframes blink {
1952
+ 50% { opacity: 0; }
1953
+ }
1954
+
1955
+ .streaming-footer {
1956
+ display: flex;
1957
+ justify-content: flex-end;
1958
+ padding: var(--spacing-md) var(--spacing-lg);
1959
+ border-top: 1px solid var(--border-color);
1960
+ background: var(--bg-tertiary);
1961
+ border-radius: 0 0 var(--radius-lg) var(--radius-lg);
1962
+ }
1963
+
1964
+ /* ============ Conversation Panel Styles ============ */
1965
+
1966
+ .ai-conversation-overlay {
1967
+ position: fixed;
1968
+ top: 0;
1969
+ left: 0;
1970
+ right: 0;
1971
+ bottom: 0;
1972
+ background: rgba(0, 0, 0, 0.85);
1973
+ z-index: 2000;
1974
+ display: flex;
1975
+ align-items: center;
1976
+ justify-content: center;
1977
+ }
1978
+
1979
+ .conversation-panel {
1980
+ background: var(--bg-secondary);
1981
+ border: 1px solid var(--border-color);
1982
+ border-radius: var(--radius-lg);
1983
+ width: 90%;
1984
+ max-width: 900px;
1985
+ height: 85vh;
1986
+ max-height: 85vh;
1987
+ display: flex;
1988
+ flex-direction: column;
1989
+ box-shadow: var(--shadow-lg);
1990
+ overflow: hidden;
1991
+ }
1992
+
1993
+ .conversation-header {
1994
+ display: flex;
1995
+ justify-content: space-between;
1996
+ align-items: center;
1997
+ padding: var(--spacing-md) var(--spacing-lg);
1998
+ border-bottom: 1px solid var(--border-color);
1999
+ background: var(--bg-tertiary);
2000
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
2001
+ }
2002
+
2003
+ .conversation-title {
2004
+ display: flex;
2005
+ align-items: center;
2006
+ gap: var(--spacing-sm);
2007
+ font-size: 16px;
2008
+ font-weight: 600;
2009
+ color: var(--text-primary);
2010
+ }
2011
+
2012
+ .conversation-mode {
2013
+ display: flex;
2014
+ align-items: center;
2015
+ gap: var(--spacing-sm);
2016
+ font-size: 12px;
2017
+ color: var(--text-secondary);
2018
+ padding: 4px 12px;
2019
+ background: var(--bg-hover);
2020
+ border-radius: 12px;
2021
+ }
2022
+
2023
+ .mode-indicator {
2024
+ width: 8px;
2025
+ height: 8px;
2026
+ border-radius: 50%;
2027
+ background: var(--text-muted);
2028
+ }
2029
+
2030
+ .mode-indicator.mode-api {
2031
+ background: var(--accent-blue);
2032
+ }
2033
+
2034
+ .mode-indicator.mode-cli {
2035
+ background: var(--accent-purple, #a855f7);
2036
+ }
2037
+
2038
+ .conversation-body {
2039
+ flex: 1 1 0;
2040
+ min-height: 0;
2041
+ overflow-y: auto;
2042
+ overflow-x: hidden;
2043
+ padding: var(--spacing-md) var(--spacing-lg);
2044
+ }
2045
+
2046
+ .conversation-entry {
2047
+ border-left: 3px solid var(--border-color);
2048
+ border-radius: var(--radius-sm);
2049
+ background: var(--bg-tertiary);
2050
+ overflow: hidden;
2051
+ margin-bottom: var(--spacing-md);
2052
+ }
2053
+
2054
+ .conversation-entry.entry-prompt {
2055
+ border-left-color: var(--accent-blue);
2056
+ }
2057
+
2058
+ .conversation-entry.entry-thinking {
2059
+ border-left-color: var(--accent-yellow);
2060
+ }
2061
+
2062
+ .conversation-entry.entry-tool {
2063
+ border-left-color: var(--accent-purple, #a855f7);
2064
+ }
2065
+
2066
+ .conversation-entry.entry-result {
2067
+ border-left-color: var(--accent-cyan, #06b6d4);
2068
+ }
2069
+
2070
+ .conversation-entry.entry-ai {
2071
+ border-left-color: var(--accent-green);
2072
+ }
2073
+
2074
+ .conversation-entry.entry-error {
2075
+ border-left-color: var(--accent-red);
2076
+ }
2077
+
2078
+ .entry-summary {
2079
+ padding: var(--spacing-sm) var(--spacing-md);
2080
+ cursor: pointer;
2081
+ display: flex;
2082
+ align-items: center;
2083
+ gap: var(--spacing-sm);
2084
+ user-select: none;
2085
+ list-style: none;
2086
+ background: var(--bg-hover);
2087
+ }
2088
+
2089
+ .entry-summary::-webkit-details-marker {
2090
+ display: none;
2091
+ }
2092
+
2093
+ .entry-summary::before {
2094
+ content: "▶";
2095
+ font-size: 10px;
2096
+ transition: transform 0.2s ease;
2097
+ color: var(--text-secondary);
2098
+ }
2099
+
2100
+ details[open] > .entry-summary::before {
2101
+ transform: rotate(90deg);
2102
+ }
2103
+
2104
+ .entry-icon {
2105
+ font-size: 14px;
2106
+ }
2107
+
2108
+ .entry-title {
2109
+ flex: 1;
2110
+ font-weight: 600;
2111
+ font-size: 13px;
2112
+ color: var(--text-primary);
2113
+ }
2114
+
2115
+ .entry-timestamp {
2116
+ font-size: 11px;
2117
+ color: var(--text-muted);
2118
+ font-family: "Consolas", "Monaco", monospace;
2119
+ }
2120
+
2121
+ .entry-badge {
2122
+ font-size: 12px;
2123
+ padding: 2px 8px;
2124
+ background: var(--bg-secondary);
2125
+ border-radius: 10px;
2126
+ color: var(--text-secondary);
2127
+ }
2128
+
2129
+ .entry-body {
2130
+ padding: var(--spacing-md);
2131
+ border-top: 1px solid var(--border-color);
2132
+ }
2133
+
2134
+ .entry-content {
2135
+ margin: 0;
2136
+ padding: var(--spacing-sm);
2137
+ background: var(--bg-primary);
2138
+ border: 1px solid var(--border-color);
2139
+ border-radius: var(--radius-sm);
2140
+ font-family: "Consolas", "Monaco", monospace;
2141
+ font-size: 12px;
2142
+ line-height: 1.5;
2143
+ white-space: pre-wrap;
2144
+ word-break: break-word;
2145
+ max-height: 300px;
2146
+ overflow-y: auto;
2147
+ color: var(--text-primary);
2148
+ }
2149
+
2150
+ .conversation-footer {
2151
+ display: flex;
2152
+ justify-content: flex-end;
2153
+ padding: var(--spacing-md) var(--spacing-lg);
2154
+ border-top: 1px solid var(--border-color);
2155
+ background: var(--bg-tertiary);
2156
+ border-radius: 0 0 var(--radius-lg) var(--radius-lg);
2157
+ }