shell-mirror 1.5.76 → 1.5.78

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shell-mirror",
3
- "version": "1.5.76",
3
+ "version": "1.5.78",
4
4
  "description": "Access your Mac shell from any device securely. Perfect for mobile coding with Claude Code CLI, Gemini CLI, and any shell tool.",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -76,7 +76,7 @@
76
76
  flex-direction: column;
77
77
  }
78
78
 
79
- /* Session Header */
79
+ /* Session Header - Unified Design */
80
80
  .session-header {
81
81
  background: #2a2a2a;
82
82
  color: #ccc;
@@ -87,64 +87,157 @@
87
87
  justify-content: space-between;
88
88
  font-size: 0.9em;
89
89
  z-index: 100;
90
+ height: 40px;
90
91
  }
91
-
92
- .session-info {
92
+
93
+ .header-left {
93
94
  display: flex;
94
95
  align-items: center;
95
- gap: 12px;
96
+ gap: 10px;
97
+ position: relative;
96
98
  }
97
-
98
- .session-name {
99
- font-weight: bold;
100
- color: #fff;
99
+
100
+ .header-center {
101
+ flex: 1;
102
+ display: flex;
103
+ justify-content: center;
101
104
  }
102
-
103
- .session-controls {
105
+
106
+ .header-right {
104
107
  display: flex;
105
108
  align-items: center;
106
109
  gap: 8px;
107
110
  }
108
-
111
+
112
+ /* Session Info Button */
113
+ .session-info-btn {
114
+ background: transparent;
115
+ border: 1px solid #444;
116
+ color: #ccc;
117
+ padding: 4px 12px;
118
+ border-radius: 4px;
119
+ cursor: pointer;
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 8px;
123
+ font-size: 0.9em;
124
+ transition: all 0.2s ease;
125
+ }
126
+
127
+ .session-info-btn:hover {
128
+ background: #3a3a3a;
129
+ border-color: #667eea;
130
+ }
131
+
132
+ .session-name {
133
+ font-weight: bold;
134
+ color: #fff;
135
+ }
136
+
137
+ .session-id {
138
+ color: #999;
139
+ font-size: 0.85em;
140
+ }
141
+
142
+ .dropdown-arrow {
143
+ color: #888;
144
+ font-size: 0.7em;
145
+ }
146
+
147
+ /* Session Info Dropdown */
148
+ .session-info-dropdown {
149
+ display: none;
150
+ position: absolute;
151
+ top: 100%;
152
+ left: 0;
153
+ margin-top: 8px;
154
+ background: #2a2a2a;
155
+ border: 1px solid #555;
156
+ border-radius: 4px;
157
+ min-width: 280px;
158
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5);
159
+ z-index: 1000;
160
+ }
161
+
162
+ .session-info-dropdown.show {
163
+ display: block;
164
+ }
165
+
166
+ .dropdown-section {
167
+ padding: 12px 16px;
168
+ }
169
+
170
+ .dropdown-divider {
171
+ height: 1px;
172
+ background: #444;
173
+ }
174
+
175
+ .session-detail-name {
176
+ font-weight: bold;
177
+ color: #fff;
178
+ margin-bottom: 4px;
179
+ }
180
+
181
+ .session-detail-id {
182
+ color: #999;
183
+ font-size: 0.85em;
184
+ font-family: monospace;
185
+ }
186
+
187
+ .connection-detail {
188
+ color: #ccc;
189
+ font-size: 0.9em;
190
+ }
191
+
192
+ .version-info {
193
+ color: #888;
194
+ font-size: 0.85em;
195
+ }
196
+
197
+ /* Sessions Dropdown */
109
198
  .session-dropdown {
110
199
  position: relative;
111
200
  display: inline-block;
112
201
  }
113
-
202
+
114
203
  .session-dropdown-btn {
115
- background: #3a3a3a;
204
+ background: transparent;
116
205
  color: #ccc;
117
- border: 1px solid #555;
118
- padding: 4px 8px;
206
+ border: 1px solid #444;
207
+ padding: 4px 12px;
119
208
  border-radius: 4px;
120
209
  cursor: pointer;
121
- font-size: 0.8em;
210
+ font-size: 0.9em;
122
211
  display: flex;
123
212
  align-items: center;
124
213
  gap: 4px;
214
+ transition: all 0.2s ease;
125
215
  }
126
-
216
+
127
217
  .session-dropdown-btn:hover {
128
- background: #4a4a4a;
218
+ background: #3a3a3a;
219
+ border-color: #667eea;
129
220
  }
130
-
221
+
131
222
  .session-dropdown-content {
132
223
  display: none;
133
224
  position: absolute;
134
225
  background: #2a2a2a;
135
226
  border: 1px solid #555;
136
227
  border-radius: 4px;
137
- right: 0;
228
+ left: 50%;
229
+ transform: translateX(-50%);
138
230
  top: 100%;
231
+ margin-top: 8px;
139
232
  min-width: 200px;
140
233
  z-index: 1000;
141
234
  box-shadow: 0 4px 8px rgba(0,0,0,0.3);
142
235
  }
143
-
236
+
144
237
  .session-dropdown-content.show {
145
238
  display: block;
146
239
  }
147
-
240
+
148
241
  .session-dropdown-item {
149
242
  padding: 8px 12px;
150
243
  cursor: pointer;
@@ -153,82 +246,79 @@
153
246
  justify-content: space-between;
154
247
  align-items: center;
155
248
  }
156
-
249
+
157
250
  .session-dropdown-item:last-child {
158
251
  border-bottom: none;
159
252
  }
160
-
253
+
161
254
  .session-dropdown-item:hover {
162
255
  background: #3a3a3a;
163
256
  }
164
-
257
+
165
258
  .session-dropdown-item.current {
166
259
  background: #4285f4;
167
260
  color: white;
168
261
  }
169
-
170
- #terminal {
171
- padding: 8px; /* Mac Terminal.app padding */
172
- background-color: #000000;
173
- height: calc(100% - 16px - 40px); /* Subtract session header height */
174
- width: calc(100% - 16px);
175
- flex: 1;
176
- }
177
- #connect-container { padding: 2em; text-align: center; }
178
- #agent-id-input { font-size: 1.2em; padding: 8px; width: 400px; margin-bottom: 1em; }
179
- #connect-btn { font-size: 1.2em; padding: 10px 20px; }
180
-
181
- /* How to Use Button */
182
- .how-to-use-btn {
183
- position: fixed;
184
- top: 20px;
185
- left: 170px;
186
- background: rgba(102, 126, 234, 0.9);
187
- color: white;
188
- border: none;
189
- border-radius: 8px;
190
- padding: 10px 16px;
262
+
263
+ /* Header Buttons */
264
+ .header-btn {
265
+ background: transparent;
266
+ border: 1px solid #444;
267
+ color: #ccc;
268
+ padding: 6px 12px;
269
+ border-radius: 4px;
191
270
  cursor: pointer;
192
- font-size: 0.9em;
193
- font-weight: 500;
194
271
  display: flex;
195
272
  align-items: center;
196
273
  gap: 6px;
197
- z-index: 10000;
198
- backdrop-filter: blur(10px);
274
+ font-size: 0.9em;
275
+ text-decoration: none;
199
276
  transition: all 0.2s ease;
200
277
  }
201
278
 
202
- .how-to-use-btn:hover {
203
- background: rgba(102, 126, 234, 1);
204
- transform: translateY(-1px);
279
+ .header-btn:hover {
280
+ background: #3a3a3a;
281
+ border-color: #667eea;
205
282
  }
206
283
 
207
- /* Back to Dashboard Button */
208
- .back-to-dashboard {
209
- position: fixed;
210
- top: 20px;
211
- right: 20px;
212
- background: rgba(66, 133, 244, 0.9);
213
- color: white;
214
- border: none;
215
- padding: 12px 20px;
216
- border-radius: 8px;
217
- font-weight: 500;
218
- cursor: pointer;
219
- z-index: 1000;
220
- transition: all 0.2s ease;
221
- display: flex;
222
- align-items: center;
223
- gap: 8px;
224
- text-decoration: none;
284
+ .help-btn .btn-text {
285
+ display: none;
225
286
  }
226
-
227
- .back-to-dashboard:hover {
228
- background: rgba(51, 103, 214, 0.9);
229
- transform: translateY(-1px);
287
+
288
+ @media (min-width: 768px) {
289
+ .help-btn .btn-text {
290
+ display: inline;
291
+ }
292
+ }
293
+
294
+ /* Dashboard button with status dot */
295
+ .dashboard-btn {
296
+ position: relative;
230
297
  }
231
298
 
299
+ .dashboard-btn::before {
300
+ content: '';
301
+ position: absolute;
302
+ top: 4px;
303
+ right: 4px;
304
+ width: 8px;
305
+ height: 8px;
306
+ border-radius: 50%;
307
+ background: #44ff44;
308
+ box-shadow: 0 0 8px rgba(68, 255, 68, 0.5);
309
+ }
310
+
311
+ #terminal {
312
+ padding: 8px; /* Mac Terminal.app padding */
313
+ background-color: #000000;
314
+ height: calc(100% - 16px - 40px); /* Subtract session header height */
315
+ width: calc(100% - 16px);
316
+ flex: 1;
317
+ }
318
+ #connect-container { padding: 2em; text-align: center; }
319
+ #agent-id-input { font-size: 1.2em; padding: 8px; width: 400px; margin-bottom: 1em; }
320
+ #connect-btn { font-size: 1.2em; padding: 10px 20px; }
321
+
232
322
  /* Connection Status Indicator */
233
323
  .connection-status {
234
324
  width: 8px;
@@ -253,32 +343,125 @@
253
343
  from { opacity: 1; }
254
344
  to { opacity: 0.4; }
255
345
  }
346
+
347
+ /* Help Modal - Tab Navigation */
348
+ .help-tabs {
349
+ display: flex;
350
+ padding: 0 24px;
351
+ border-bottom: 1px solid #eee;
352
+ background: #f8f9fa;
353
+ }
354
+
355
+ .help-tab {
356
+ padding: 12px 20px;
357
+ background: transparent;
358
+ border: none;
359
+ border-bottom: 3px solid transparent;
360
+ cursor: pointer;
361
+ font-size: 0.9rem;
362
+ color: #666;
363
+ transition: all 0.2s ease;
364
+ }
365
+
366
+ .help-tab:hover {
367
+ color: #333;
368
+ background: rgba(102, 126, 234, 0.05);
369
+ }
370
+
371
+ .help-tab.active {
372
+ color: #667eea;
373
+ border-bottom-color: #667eea;
374
+ font-weight: 600;
375
+ }
376
+
377
+ /* Help Modal - Tab Content */
378
+ .help-tab-content {
379
+ display: none;
380
+ }
381
+
382
+ .help-tab-content.active {
383
+ display: block;
384
+ }
385
+
386
+ /* Help Modal - Content Sections */
387
+ .help-section {
388
+ margin-bottom: 24px;
389
+ }
390
+
391
+ .help-section h4 {
392
+ color: #333;
393
+ font-size: 1rem;
394
+ margin-bottom: 12px;
395
+ }
396
+
397
+ .help-section p {
398
+ color: #666;
399
+ line-height: 1.6;
400
+ margin-bottom: 8px;
401
+ }
402
+
403
+ .help-section ul {
404
+ list-style: none;
405
+ padding: 0;
406
+ margin: 8px 0;
407
+ }
408
+
409
+ .help-section li {
410
+ padding: 4px 0;
411
+ color: #666;
412
+ line-height: 1.6;
413
+ }
414
+
415
+ /* Help Modal - Mobile Responsiveness */
416
+ @media (max-width: 768px) {
417
+ .help-tabs {
418
+ overflow-x: auto;
419
+ -webkit-overflow-scrolling: touch;
420
+ }
421
+
422
+ .help-tab {
423
+ font-size: 0.8rem;
424
+ padding: 10px 12px;
425
+ white-space: nowrap;
426
+ }
427
+ }
256
428
  </style>
257
429
  </head>
258
430
  <body>
259
- <!-- Back to Dashboard Button -->
260
- <a href="/app/dashboard.html" class="back-to-dashboard" id="dashboard-btn">
261
- <div class="connection-status" id="connection-status"></div>
262
- <span>←</span>
263
- <span>Dashboard</span>
264
- </a>
265
-
266
- <!-- How to Use Button -->
267
- <button class="how-to-use-btn" id="how-to-use-btn" onclick="showHelpModal()">
268
- 📖 How to Use
269
- </button>
270
-
271
431
  <div id="connect-container">
272
432
  <h2>Terminal Mirror</h2>
273
433
  <p>Connecting to terminal...</p>
274
434
  </div>
275
435
  <div id="terminal-container">
276
436
  <div class="session-header" id="session-header" style="display: none;">
277
- <div class="session-info">
278
- <span class="session-name" id="session-name">Terminal Session</span>
279
- <span class="session-id" id="session-id"></span>
437
+ <div class="header-left">
438
+ <div class="connection-status" id="connection-status"></div>
439
+ <button class="session-info-btn" id="session-info-btn">
440
+ <span class="session-name" id="session-name">Terminal Session</span>
441
+ <span class="session-id" id="session-id"></span>
442
+ <span class="dropdown-arrow">▼</span>
443
+ </button>
444
+
445
+ <!-- Session Info Dropdown -->
446
+ <div class="session-info-dropdown" id="session-info-dropdown">
447
+ <div class="dropdown-section">
448
+ <div class="session-detail-name" id="detail-name">Session 1</div>
449
+ <div class="session-detail-id" id="detail-id">ses_1764...</div>
450
+ </div>
451
+ <div class="dropdown-divider"></div>
452
+ <div class="dropdown-section">
453
+ <div class="connection-detail" id="connection-detail">
454
+ 🟢 Connected via WebRTC
455
+ </div>
456
+ </div>
457
+ <div class="dropdown-divider"></div>
458
+ <div class="dropdown-section version-info">
459
+ <div id="version-info-dropdown">v1.5.76 • Built Nov 26, 2025</div>
460
+ </div>
461
+ </div>
280
462
  </div>
281
- <div class="session-controls">
463
+
464
+ <div class="header-center">
282
465
  <div class="session-dropdown">
283
466
  <button class="session-dropdown-btn" id="session-dropdown-btn">
284
467
  <span>Sessions</span>
@@ -291,62 +474,86 @@
291
474
  </div>
292
475
  </div>
293
476
  </div>
477
+
478
+ <div class="header-right">
479
+ <button class="header-btn help-btn" onclick="showHelpModal()">
480
+ <span>📖</span>
481
+ <span class="btn-text">Help</span>
482
+ </button>
483
+ <a href="/app/dashboard.html" class="header-btn dashboard-btn">
484
+ <span>📊</span>
485
+ </a>
486
+ </div>
294
487
  </div>
295
488
  <div id="terminal"></div>
296
489
  </div>
297
490
 
298
491
  <!-- Help Modal -->
299
492
  <div id="help-modal" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.8); align-items: center; justify-content: center; z-index: 20000;">
300
- <div style="background: white; border-radius: 12px; max-width: 500px; width: 90%; max-height: 80vh; overflow: hidden;">
493
+ <div style="background: white; border-radius: 12px; max-width: 600px; width: 90%; max-height: 80vh; overflow: hidden;">
494
+ <!-- Header -->
301
495
  <div style="padding: 20px 24px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;">
302
- <h3 style="margin: 0; font-size: 1.2rem; color: #333;">🚀 How to Use Shell Mirror</h3>
496
+ <h3 style="margin: 0; font-size: 1.2rem; color: #333;">🚀 Shell Mirror Terminal</h3>
303
497
  <button onclick="closeHelpModal()" style="background: none; border: none; font-size: 1.5rem; cursor: pointer; padding: 0; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border-radius: 50%; color: #666;">×</button>
304
498
  </div>
499
+
500
+ <!-- Tab Navigation -->
501
+ <div class="help-tabs">
502
+ <button class="help-tab active" onclick="showHelpTab('sessions')">Sessions</button>
503
+ <button class="help-tab" onclick="showHelpTab('help')">Troubleshooting</button>
504
+ </div>
505
+
506
+ <!-- Tab Content -->
305
507
  <div style="padding: 24px; max-height: 60vh; overflow-y: auto;">
306
- <p style="margin-top: 0; margin-bottom: 24px; color: #666; font-size: 1rem;">Get started in 2 easy steps:</p>
307
-
308
- <div style="display: flex; gap: 16px; margin-bottom: 24px; align-items: flex-start;">
309
- <div style="flex-shrink: 0; width: 32px; height: 32px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 0.95rem;">1</div>
310
- <div style="flex: 1;">
311
- <h4 style="margin: 0 0 12px 0; font-size: 1.05rem; font-weight: 600; color: #333;">Install the agent</h4>
312
- <div style="background: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px 14px; display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px;">
313
- <code style="font-family: 'Monaco', 'Menlo', 'Courier New', monospace; font-size: 0.9rem; color: #1a1a1a; flex: 1;">npm install -g shell-mirror</code>
314
- <button onclick="copyToClipboard('npm install -g shell-mirror', this)" style="background: #667eea; color: white; border: none; border-radius: 6px; padding: 6px 12px; font-size: 0.85rem; cursor: pointer; transition: all 0.2s ease; flex-shrink: 0;">Copy</button>
315
- </div>
316
- </div>
317
- </div>
508
+ <!-- Sessions Tab -->
509
+ <div id="tab-sessions" class="help-tab-content active">
510
+ <p style="margin-top: 0; margin-bottom: 16px;">Sessions let you run multiple terminals simultaneously.</p>
318
511
 
319
- <div style="display: flex; gap: 16px; margin-bottom: 24px; align-items: flex-start;">
320
- <div style="flex-shrink: 0; width: 32px; height: 32px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 0.95rem;">2</div>
321
- <div style="flex: 1;">
322
- <h4 style="margin: 0 0 12px 0; font-size: 1.05rem; font-weight: 600; color: #333;">Run the agent</h4>
323
- <div style="background: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px 14px; display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px;">
324
- <code style="font-family: 'Monaco', 'Menlo', 'Courier New', monospace; font-size: 0.9rem; color: #1a1a1a; flex: 1;">shell-mirror</code>
325
- <button onclick="copyToClipboard('shell-mirror', this)" style="background: #667eea; color: white; border: none; border-radius: 6px; padding: 6px 12px; font-size: 0.85rem; cursor: pointer; transition: all 0.2s ease; flex-shrink: 0;">Copy</button>
326
- </div>
327
- <p style="margin: 8px 0 0 0; font-size: 0.85rem; color: #666; font-style: italic;">The agent will automatically connect to your dashboard</p>
328
- </div>
512
+ <h4 style="margin-top: 20px; margin-bottom: 8px;">Creating</h4>
513
+ <ul style="list-style: none; padding: 0; margin: 0;">
514
+ <li>• Tap "Sessions" "+ New Session"</li>
515
+ <li>• Each session runs independently</li>
516
+ </ul>
517
+
518
+ <h4 style="margin-top: 20px; margin-bottom: 8px;">Switching</h4>
519
+ <ul style="list-style: none; padding: 0; margin: 0;">
520
+ <li>• Tap "Sessions" dropdown</li>
521
+ <li>• Select any session</li>
522
+ <li>• Your processes keep running in background</li>
523
+ </ul>
524
+
525
+ <h4 style="margin-top: 20px; margin-bottom: 8px;">Limits</h4>
526
+ <ul style="list-style: none; padding: 0; margin: 0;">
527
+ <li>• Max 10 sessions per Mac</li>
528
+ <li>• Auto-deleted after 24h inactive</li>
529
+ </ul>
329
530
  </div>
330
531
 
331
- <div style="margin-top: 32px; padding: 16px; background: #f8f9fa; border-radius: 8px; border-left: 4px solid #667eea;">
332
- <h4 style="margin: 0 0 12px 0; font-size: 1rem; font-weight: 600; color: #333;">💡 Troubleshooting</h4>
333
- <ul style="margin: 0; padding-left: 20px; list-style-type: disc;">
334
- <li style="margin-bottom: 8px; color: #555; font-size: 0.9rem;">Make sure you're logged in with the same Google account</li>
335
- <li style="margin-bottom: 8px; color: #555; font-size: 0.9rem;">Check that the agent is running in your terminal</li>
336
- <li style="margin-bottom: 0; color: #555; font-size: 0.9rem;">Refresh your dashboard after starting the agent</li>
532
+ <!-- Troubleshooting Tab -->
533
+ <div id="tab-help" class="help-tab-content" style="display: none;">
534
+ <h4 style="margin-top: 0; margin-bottom: 8px;">Connection stuck?</h4>
535
+ <ul style="list-style: none; padding: 0; margin: 0 0 20px 0;">
536
+ <li>• Wait 10 seconds for auto-retry</li>
537
+ <li>• Still red? Return to Dashboard Reconnect</li>
538
+ </ul>
539
+
540
+ <h4 style="margin-top: 20px; margin-bottom: 8px;">Slow connection?</h4>
541
+ <ul style="list-style: none; padding: 0; margin: 0 0 20px 0;">
542
+ <li>• App tries: Local network → WebRTC → Fallback</li>
543
+ <li>• First connect may take 30 seconds</li>
544
+ <li>• WebRTC works best (100-500ms)</li>
545
+ </ul>
546
+
547
+ <h4 style="margin-top: 20px; margin-bottom: 8px;">Behind corporate firewall?</h4>
548
+ <ul style="list-style: none; padding: 0; margin: 0;">
549
+ <li>• May need IT to whitelist STUN servers</li>
550
+ <li>• Contact: stun.l.google.com port 19302</li>
337
551
  </ul>
338
552
  </div>
339
553
  </div>
340
554
  </div>
341
555
  </div>
342
556
 
343
- <!-- Version Footer -->
344
- <footer style="background: #ff6b35; color: white; text-align: center; padding: 10px 0; font-size: 0.8rem; position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000;">
345
- <div style="max-width: 1200px; margin: 0 auto;">
346
- <p id="terminal-version-info">Terminal Mirror • Loading version...</p>
347
- </div>
348
- </footer>
349
-
350
557
  <script>
351
558
  // Help Modal Functions
352
559
  function showHelpModal() {
@@ -359,16 +566,27 @@
359
566
  modal.style.display = 'none';
360
567
  }
361
568
 
362
- function copyToClipboard(text, button) {
363
- navigator.clipboard.writeText(text).then(() => {
364
- const originalText = button.textContent;
365
- button.textContent = 'Copied!';
366
- setTimeout(() => {
367
- button.textContent = originalText;
368
- }, 2000);
369
- }).catch(err => {
370
- console.error('Failed to copy:', err);
569
+ function showHelpTab(tabName) {
570
+ // Hide all tab content
571
+ document.querySelectorAll('.help-tab-content').forEach(content => {
572
+ content.classList.remove('active');
573
+ content.style.display = 'none';
574
+ });
575
+
576
+ // Remove active from all tab buttons
577
+ document.querySelectorAll('.help-tab').forEach(btn => {
578
+ btn.classList.remove('active');
371
579
  });
580
+
581
+ // Show selected tab content
582
+ const selectedContent = document.getElementById('tab-' + tabName);
583
+ if (selectedContent) {
584
+ selectedContent.classList.add('active');
585
+ selectedContent.style.display = 'block';
586
+ }
587
+
588
+ // Activate corresponding button
589
+ event.target.classList.add('active');
372
590
  }
373
591
 
374
592
  // Close modal when clicking outside
@@ -155,7 +155,7 @@ const chunkAssembler = {
155
155
  function updateConnectionStatus(status) {
156
156
  const statusElement = document.getElementById('connection-status');
157
157
  if (!statusElement) return;
158
-
158
+
159
159
  statusElement.className = 'connection-status';
160
160
  switch(status) {
161
161
  case 'connecting':
@@ -169,6 +169,9 @@ function updateConnectionStatus(status) {
169
169
  // Default red styling already applied
170
170
  break;
171
171
  }
172
+
173
+ // Update connection detail in dropdown
174
+ updateConnectionDetail(status);
172
175
  }
173
176
 
174
177
  // Cleanup timer for chunk assembler
@@ -217,27 +220,63 @@ window.addEventListener('load', () => {
217
220
  }
218
221
  });
219
222
 
220
- // Load version info for footer
223
+ // Load version info into dropdown
221
224
  async function loadVersionInfo() {
222
225
  try {
223
226
  const response = await fetch('/build-info.json');
224
227
  const buildInfo = await response.json();
225
- const versionElement = document.getElementById('terminal-version-info');
226
- const footerElement = versionElement?.parentElement?.parentElement; // Get the footer element
227
-
228
- if (versionElement && buildInfo) {
229
- const buildDateTime = new Date(buildInfo.buildTime).toLocaleString();
230
- versionElement.textContent = `Terminal Mirror v${buildInfo.version} • Built ${buildDateTime}`;
231
-
232
- // Apply random footer color from build info
233
- if (footerElement && buildInfo.footerColor) {
234
- footerElement.style.background = buildInfo.footerColor;
235
- console.log(`🎨 Applied footer color: ${buildInfo.footerColor}`);
228
+
229
+ if (buildInfo) {
230
+ const buildDateTime = new Date(buildInfo.buildTime).toLocaleString('en-US', {
231
+ month: 'short',
232
+ day: 'numeric',
233
+ year: 'numeric',
234
+ hour: '2-digit',
235
+ minute: '2-digit'
236
+ });
237
+
238
+ const versionElement = document.getElementById('version-info-dropdown');
239
+ if (versionElement) {
240
+ versionElement.textContent = `v${buildInfo.version} • Built ${buildDateTime}`;
236
241
  }
237
242
  }
238
243
  } catch (error) {
239
244
  console.log('Could not load build info for terminal:', error);
240
- // Keep default version and color if build-info.json not available
245
+ }
246
+ }
247
+
248
+ // Update connection detail in dropdown
249
+ function updateConnectionDetail(status, method = 'WebRTC') {
250
+ const detail = document.getElementById('connection-detail');
251
+ if (!detail) return;
252
+
253
+ const statusIcons = {
254
+ connected: '🟢',
255
+ connecting: '🟡',
256
+ disconnected: '🔴'
257
+ };
258
+
259
+ const statusTexts = {
260
+ connected: 'Connected',
261
+ connecting: 'Connecting',
262
+ disconnected: 'Disconnected'
263
+ };
264
+
265
+ detail.textContent = `${statusIcons[status] || '⚪'} ${statusTexts[status] || 'Unknown'} via ${method}`;
266
+ }
267
+
268
+ // Update session details in dropdown
269
+ function updateSessionDetails() {
270
+ if (currentSession) {
271
+ const detailName = document.getElementById('detail-name');
272
+ const detailId = document.getElementById('detail-id');
273
+
274
+ if (detailName) {
275
+ detailName.textContent = currentSession.name || 'Terminal Session';
276
+ }
277
+ if (detailId) {
278
+ detailId.textContent = `ID: ${currentSession.id}`;
279
+ }
241
280
  }
242
281
  }
243
282
 
@@ -920,15 +959,18 @@ function updateSessionDisplay() {
920
959
  const sessionHeader = document.getElementById('session-header');
921
960
  const sessionName = document.getElementById('session-name');
922
961
  const sessionId = document.getElementById('session-id');
923
-
962
+
924
963
  if (currentSession) {
925
964
  sessionHeader.style.display = 'flex';
926
965
  sessionName.textContent = currentSession.name;
927
966
  sessionId.textContent = `(${currentSession.id.substring(0, 8)}...)`;
928
-
967
+
929
968
  // Update available sessions dropdown
930
969
  updateSessionDropdown();
931
-
970
+
971
+ // Update session details in dropdown
972
+ updateSessionDetails();
973
+
932
974
  console.log('[CLIENT] 📋 Session display updated:', currentSession);
933
975
  }
934
976
  }
@@ -998,22 +1040,49 @@ function createNewSession() {
998
1040
  window.location.href = url.toString();
999
1041
  }
1000
1042
 
1001
- // Setup dropdown toggle
1043
+ // Setup dropdown toggles
1002
1044
  document.addEventListener('DOMContentLoaded', () => {
1045
+ // Session info dropdown
1046
+ const sessionInfoBtn = document.getElementById('session-info-btn');
1047
+ const sessionInfoDropdown = document.getElementById('session-info-dropdown');
1048
+
1049
+ // Sessions menu dropdown
1003
1050
  const dropdownBtn = document.getElementById('session-dropdown-btn');
1004
1051
  const dropdownContent = document.getElementById('session-dropdown-content');
1005
-
1052
+
1053
+ // Session info dropdown toggle
1054
+ if (sessionInfoBtn && sessionInfoDropdown) {
1055
+ sessionInfoBtn.onclick = (e) => {
1056
+ e.stopPropagation();
1057
+ sessionInfoDropdown.classList.toggle('show');
1058
+ // Close sessions dropdown if open
1059
+ if (dropdownContent) {
1060
+ dropdownContent.classList.remove('show');
1061
+ }
1062
+ };
1063
+ }
1064
+
1065
+ // Sessions menu dropdown toggle
1006
1066
  if (dropdownBtn && dropdownContent) {
1007
1067
  dropdownBtn.onclick = (e) => {
1008
1068
  e.stopPropagation();
1009
1069
  dropdownContent.classList.toggle('show');
1070
+ // Close session info dropdown if open
1071
+ if (sessionInfoDropdown) {
1072
+ sessionInfoDropdown.classList.remove('show');
1073
+ }
1010
1074
  };
1011
-
1012
- // Close dropdown when clicking outside
1013
- document.addEventListener('click', () => {
1014
- dropdownContent.classList.remove('show');
1015
- });
1016
1075
  }
1076
+
1077
+ // Close both dropdowns when clicking outside
1078
+ document.addEventListener('click', () => {
1079
+ if (dropdownContent) {
1080
+ dropdownContent.classList.remove('show');
1081
+ }
1082
+ if (sessionInfoDropdown) {
1083
+ sessionInfoDropdown.classList.remove('show');
1084
+ }
1085
+ });
1017
1086
  });
1018
1087
 
1019
1088
  // Handle session-related data channel messages