@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,495 @@
1
+ /* ============ Dashboard 專用樣式 ============ */
2
+
3
+ .dashboard-body {
4
+ overflow-y: auto;
5
+ min-height: 100vh;
6
+ padding-bottom: 60px;
7
+ }
8
+
9
+ /* ============ Dashboard Header ============ */
10
+
11
+ .dashboard-header {
12
+ display: flex;
13
+ justify-content: space-between;
14
+ align-items: center;
15
+ padding: var(--spacing-md) var(--spacing-lg);
16
+ background: var(--bg-secondary);
17
+ border-bottom: 1px solid var(--border-color);
18
+ position: sticky;
19
+ top: 0;
20
+ z-index: 100;
21
+ }
22
+
23
+ .header-left {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: var(--spacing-md);
27
+ }
28
+
29
+ .dashboard-title {
30
+ font-size: 20px;
31
+ font-weight: 600;
32
+ color: var(--text-primary);
33
+ display: flex;
34
+ align-items: center;
35
+ gap: var(--spacing-sm);
36
+ }
37
+
38
+ .header-right {
39
+ display: flex;
40
+ align-items: center;
41
+ gap: var(--spacing-md);
42
+ }
43
+
44
+ .connection-indicator {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: var(--spacing-sm);
48
+ padding: var(--spacing-xs) var(--spacing-sm);
49
+ background: var(--bg-tertiary);
50
+ border-radius: var(--radius-sm);
51
+ font-size: 12px;
52
+ }
53
+
54
+ .connection-indicator .status-dot {
55
+ width: 8px;
56
+ height: 8px;
57
+ border-radius: 50%;
58
+ background: var(--text-muted);
59
+ animation: pulse 2s ease-in-out infinite;
60
+ }
61
+
62
+ .connection-indicator.connected .status-dot {
63
+ background: var(--accent-green);
64
+ }
65
+
66
+ .connection-indicator.disconnected .status-dot {
67
+ background: var(--accent-red);
68
+ animation: none;
69
+ }
70
+
71
+ /* ============ 統計摘要 ============ */
72
+
73
+ .stats-summary {
74
+ display: flex;
75
+ gap: var(--spacing-md);
76
+ padding: var(--spacing-lg);
77
+ flex-wrap: wrap;
78
+ }
79
+
80
+ .stat-card {
81
+ flex: 1;
82
+ min-width: 150px;
83
+ display: flex;
84
+ align-items: center;
85
+ gap: var(--spacing-md);
86
+ padding: var(--spacing-md) var(--spacing-lg);
87
+ background: var(--bg-secondary);
88
+ border: 1px solid var(--border-color);
89
+ border-radius: var(--radius-md);
90
+ transition: all 0.2s ease;
91
+ }
92
+
93
+ .stat-card:hover {
94
+ border-color: var(--accent-blue);
95
+ transform: translateY(-2px);
96
+ box-shadow: var(--shadow-md);
97
+ }
98
+
99
+ .stat-icon {
100
+ font-size: 32px;
101
+ }
102
+
103
+ .stat-info {
104
+ display: flex;
105
+ flex-direction: column;
106
+ }
107
+
108
+ .stat-value {
109
+ font-size: 24px;
110
+ font-weight: 700;
111
+ color: var(--text-primary);
112
+ }
113
+
114
+ .stat-label {
115
+ font-size: 12px;
116
+ color: var(--text-secondary);
117
+ }
118
+
119
+ /* ============ 專案容器 ============ */
120
+
121
+ .projects-container {
122
+ padding: 0 var(--spacing-lg);
123
+ }
124
+
125
+ .projects-header {
126
+ display: flex;
127
+ justify-content: space-between;
128
+ align-items: center;
129
+ margin-bottom: var(--spacing-md);
130
+ }
131
+
132
+ .section-title {
133
+ font-size: 16px;
134
+ font-weight: 600;
135
+ color: var(--text-primary);
136
+ display: flex;
137
+ align-items: center;
138
+ gap: var(--spacing-sm);
139
+ }
140
+
141
+ .filter-controls {
142
+ display: flex;
143
+ gap: var(--spacing-sm);
144
+ }
145
+
146
+ .search-input {
147
+ padding: var(--spacing-sm) var(--spacing-md);
148
+ background: var(--bg-tertiary);
149
+ border: 1px solid var(--border-color);
150
+ border-radius: var(--radius-sm);
151
+ color: var(--text-primary);
152
+ font-size: 13px;
153
+ width: 200px;
154
+ transition: all 0.2s ease;
155
+ }
156
+
157
+ .search-input:focus {
158
+ outline: none;
159
+ border-color: var(--accent-blue);
160
+ }
161
+
162
+ .search-input::placeholder {
163
+ color: var(--text-muted);
164
+ }
165
+
166
+ /* ============ 專案卡片網格 ============ */
167
+
168
+ .projects-grid {
169
+ display: grid;
170
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
171
+ gap: var(--spacing-md);
172
+ }
173
+
174
+ /* ============ 專案卡片 ============ */
175
+
176
+ .project-card {
177
+ background: var(--bg-secondary);
178
+ border: 1px solid var(--border-color);
179
+ border-radius: var(--radius-md);
180
+ overflow: hidden;
181
+ cursor: pointer;
182
+ transition: all 0.3s ease;
183
+ opacity: 1;
184
+ transform: translateY(0);
185
+ }
186
+
187
+ /* 淡入動畫 */
188
+ .project-card.fade-in {
189
+ animation: projectFadeIn 0.3s ease forwards;
190
+ }
191
+
192
+ /* 淡出動畫 */
193
+ .project-card.fade-out {
194
+ animation: projectFadeOut 0.3s ease forwards;
195
+ }
196
+
197
+ @keyframes projectFadeIn {
198
+ from {
199
+ opacity: 0;
200
+ transform: translateY(-10px);
201
+ }
202
+ to {
203
+ opacity: 1;
204
+ transform: translateY(0);
205
+ }
206
+ }
207
+
208
+ @keyframes projectFadeOut {
209
+ from {
210
+ opacity: 1;
211
+ transform: translateY(0);
212
+ }
213
+ to {
214
+ opacity: 0;
215
+ transform: translateY(-10px);
216
+ }
217
+ }
218
+
219
+ .project-card:hover {
220
+ border-color: var(--accent-blue);
221
+ transform: translateY(-2px);
222
+ box-shadow: var(--shadow-md);
223
+ }
224
+
225
+ .project-card.has-active {
226
+ border-left: 3px solid var(--accent-green);
227
+ }
228
+
229
+ .project-card-header {
230
+ display: flex;
231
+ justify-content: space-between;
232
+ align-items: flex-start;
233
+ padding: var(--spacing-md);
234
+ background: var(--bg-tertiary);
235
+ transition: background 0.2s ease;
236
+ border-bottom: 1px solid var(--border-color);
237
+ }
238
+
239
+ .project-name {
240
+ font-size: 15px;
241
+ font-weight: 600;
242
+ color: var(--text-primary);
243
+ display: flex;
244
+ align-items: center;
245
+ gap: var(--spacing-sm);
246
+ }
247
+
248
+ .project-name .icon {
249
+ font-size: 16px;
250
+ }
251
+
252
+ .project-badge {
253
+ padding: 2px 8px;
254
+ border-radius: var(--radius-sm);
255
+ font-size: 11px;
256
+ font-weight: 600;
257
+ }
258
+
259
+ .project-badge.active {
260
+ background: rgba(78, 201, 176, 0.2);
261
+ color: var(--accent-green);
262
+ }
263
+
264
+ .project-badge.idle {
265
+ background: rgba(150, 150, 150, 0.2);
266
+ color: var(--text-secondary);
267
+ }
268
+
269
+ .project-card-body {
270
+ padding: var(--spacing-md);
271
+ }
272
+
273
+ .project-path {
274
+ font-size: 11px;
275
+ color: var(--text-muted);
276
+ margin-bottom: var(--spacing-sm);
277
+ white-space: nowrap;
278
+ overflow: hidden;
279
+ text-overflow: ellipsis;
280
+ }
281
+
282
+ .project-stats {
283
+ display: flex;
284
+ gap: var(--spacing-md);
285
+ margin-bottom: var(--spacing-sm);
286
+ }
287
+
288
+ .project-stat {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: var(--spacing-xs);
292
+ font-size: 12px;
293
+ color: var(--text-secondary);
294
+ transition: all 0.2s ease;
295
+ }
296
+
297
+ .project-stat .value {
298
+ font-weight: 600;
299
+ color: var(--text-primary);
300
+ transition: color 0.2s ease;
301
+ }
302
+
303
+ .project-stat.active .value {
304
+ color: var(--accent-green);
305
+ }
306
+
307
+ .project-sessions {
308
+ border-top: 1px solid var(--border-color);
309
+ padding-top: var(--spacing-sm);
310
+ margin-top: var(--spacing-sm);
311
+ }
312
+
313
+ .session-list {
314
+ display: flex;
315
+ flex-direction: column;
316
+ gap: var(--spacing-xs);
317
+ max-height: 120px;
318
+ overflow-y: auto;
319
+ }
320
+
321
+ .session-item {
322
+ display: flex;
323
+ justify-content: space-between;
324
+ align-items: center;
325
+ padding: var(--spacing-xs) var(--spacing-sm);
326
+ background: var(--bg-primary);
327
+ border-radius: var(--radius-sm);
328
+ font-size: 11px;
329
+ transition: background 0.2s ease;
330
+ }
331
+
332
+ .session-item:hover {
333
+ background: var(--bg-hover);
334
+ }
335
+
336
+ .session-item.active {
337
+ border-left: 2px solid var(--accent-green);
338
+ }
339
+
340
+ .session-item.timeout {
341
+ opacity: 0.6;
342
+ }
343
+
344
+ .session-summary {
345
+ flex: 1;
346
+ white-space: nowrap;
347
+ overflow: hidden;
348
+ text-overflow: ellipsis;
349
+ color: var(--text-primary);
350
+ }
351
+
352
+ .session-status {
353
+ padding: 1px 6px;
354
+ border-radius: var(--radius-sm);
355
+ font-size: 10px;
356
+ font-weight: 600;
357
+ }
358
+
359
+ .session-status.waiting {
360
+ background: rgba(255, 152, 0, 0.2);
361
+ color: #ff9800;
362
+ }
363
+
364
+ .session-status.active {
365
+ background: rgba(78, 201, 176, 0.2);
366
+ color: var(--accent-green);
367
+ }
368
+
369
+ .session-status.completed {
370
+ background: rgba(0, 122, 204, 0.2);
371
+ color: var(--accent-blue);
372
+ }
373
+
374
+ .session-status.timeout {
375
+ background: rgba(244, 135, 113, 0.2);
376
+ color: var(--accent-red);
377
+ }
378
+
379
+ /* ============ Loading & Empty States ============ */
380
+
381
+ .loading-placeholder {
382
+ grid-column: 1 / -1;
383
+ display: flex;
384
+ flex-direction: column;
385
+ align-items: center;
386
+ justify-content: center;
387
+ padding: var(--spacing-xl);
388
+ color: var(--text-secondary);
389
+ }
390
+
391
+ .loading-placeholder .icon {
392
+ font-size: 48px;
393
+ animation: pulse 1.5s ease-in-out infinite;
394
+ }
395
+
396
+ .empty-state {
397
+ display: flex;
398
+ flex-direction: column;
399
+ align-items: center;
400
+ justify-content: center;
401
+ padding: var(--spacing-xl);
402
+ text-align: center;
403
+ color: var(--text-secondary);
404
+ }
405
+
406
+ .empty-icon {
407
+ font-size: 64px;
408
+ margin-bottom: var(--spacing-md);
409
+ }
410
+
411
+ .empty-state h3 {
412
+ font-size: 18px;
413
+ font-weight: 600;
414
+ color: var(--text-primary);
415
+ margin-bottom: var(--spacing-sm);
416
+ }
417
+
418
+ .empty-state p {
419
+ font-size: 13px;
420
+ color: var(--text-muted);
421
+ }
422
+
423
+ /* ============ 響應式設計 ============ */
424
+
425
+ @media (max-width: 768px) {
426
+ .dashboard-header {
427
+ flex-direction: column;
428
+ gap: var(--spacing-md);
429
+ }
430
+
431
+ .header-left,
432
+ .header-right {
433
+ width: 100%;
434
+ justify-content: center;
435
+ }
436
+
437
+ .stats-summary {
438
+ flex-direction: column;
439
+ }
440
+
441
+ .stat-card {
442
+ min-width: 100%;
443
+ }
444
+
445
+ .projects-grid {
446
+ grid-template-columns: 1fr;
447
+ }
448
+
449
+ .projects-header {
450
+ flex-direction: column;
451
+ gap: var(--spacing-sm);
452
+ align-items: flex-start;
453
+ }
454
+
455
+ .search-input {
456
+ width: 100%;
457
+ }
458
+ }
459
+
460
+ /* ============ 動畫 ============ */
461
+
462
+ @keyframes fadeIn {
463
+ from {
464
+ opacity: 0;
465
+ transform: translateY(10px);
466
+ }
467
+ to {
468
+ opacity: 1;
469
+ transform: translateY(0);
470
+ }
471
+ }
472
+
473
+ .project-card {
474
+ animation: fadeIn 0.3s ease;
475
+ }
476
+
477
+ /* ============ 滾動條樣式 ============ */
478
+
479
+ .session-list::-webkit-scrollbar {
480
+ width: 6px;
481
+ }
482
+
483
+ .session-list::-webkit-scrollbar-track {
484
+ background: var(--bg-primary);
485
+ border-radius: 3px;
486
+ }
487
+
488
+ .session-list::-webkit-scrollbar-thumb {
489
+ background: var(--border-color);
490
+ border-radius: 3px;
491
+ }
492
+
493
+ .session-list::-webkit-scrollbar-thumb:hover {
494
+ background: var(--text-muted);
495
+ }
@@ -0,0 +1,95 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-TW">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>📊 User Feedback Dashboard</title>
7
+ <link rel="icon" type="image/svg+xml" href="favicon.svg">
8
+ <script src="/socket.io.min.js"></script>
9
+ <!-- Navbar Component -->
10
+ <link rel="stylesheet" href="/components/navbar.css">
11
+ <link rel="stylesheet" href="style.css">
12
+ <link rel="stylesheet" href="dashboard.css">
13
+ </head>
14
+ <body class="dashboard-body">
15
+ <!-- Unified Navigation Bar (injected by navbar.js) -->
16
+
17
+ <!-- Dashboard 標題區 -->
18
+ <header class="dashboard-header" style="margin-top: 20px;">
19
+ <div class="header-left">
20
+ <h1 class="dashboard-title">
21
+ <span class="icon">📊</span>
22
+ User Feedback Dashboard
23
+ </h1>
24
+ <span id="version-display" class="version-display">v--</span>
25
+ </div>
26
+ <div class="header-right">
27
+ <div class="connection-indicator" id="connectionStatus">
28
+ <span class="status-dot"></span>
29
+ <span class="status-text">連接中...</span>
30
+ </div>
31
+ <button id="refreshBtn" class="btn btn-secondary" title="重新整理">
32
+ <span class="icon">🔄</span>
33
+ 重新整理
34
+ </button>
35
+ </div>
36
+ </header>
37
+
38
+ <!-- 統計摘要 -->
39
+ <section class="stats-summary">
40
+ <div class="stat-card">
41
+ <div class="stat-icon">📁</div>
42
+ <div class="stat-info">
43
+ <div class="stat-value" id="totalProjects">0</div>
44
+ <div class="stat-label">專案數</div>
45
+ </div>
46
+ </div>
47
+ <div class="stat-card">
48
+ <div class="stat-icon">⏳</div>
49
+ <div class="stat-info">
50
+ <div class="stat-value" id="activeSessions">0</div>
51
+ <div class="stat-label">等待回饋</div>
52
+ </div>
53
+ </div>
54
+ <div class="stat-card">
55
+ <div class="stat-icon">✅</div>
56
+ <div class="stat-info">
57
+ <div class="stat-value" id="completedSessions">0</div>
58
+ <div class="stat-label">已完成</div>
59
+ </div>
60
+ </div>
61
+ </section>
62
+
63
+ <!-- 專案列表 -->
64
+ <main class="projects-container">
65
+ <div class="projects-header">
66
+ <h2 class="section-title">
67
+ <span class="icon">📂</span>
68
+ 專案列表
69
+ </h2>
70
+ <div class="filter-controls">
71
+ <input type="text" id="searchInput" class="search-input" placeholder="搜尋專案...">
72
+ </div>
73
+ </div>
74
+
75
+ <div id="projectsList" class="projects-grid">
76
+ <!-- 專案卡片將由 JavaScript 動態生成 -->
77
+ <div class="loading-placeholder">
78
+ <span class="icon">⏳</span>
79
+ <p>載入專案中...</p>
80
+ </div>
81
+ </div>
82
+ </main>
83
+
84
+ <!-- 空狀態顯示 -->
85
+ <div id="emptyState" class="empty-state" style="display: none;">
86
+ <div class="empty-icon">📭</div>
87
+ <h3>尚無專案</h3>
88
+ <p>當 AI 開始發送工作匯報時,專案將自動顯示在此處</p>
89
+ </div>
90
+
91
+ <!-- Scripts -->
92
+ <script src="/components/navbar.js"></script>
93
+ <script src="dashboard.js"></script>
94
+ </body>
95
+ </html>