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 +1 -1
- package/public/app/terminal.html +356 -138
- package/public/app/terminal.js +93 -24
package/package.json
CHANGED
package/public/app/terminal.html
CHANGED
|
@@ -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
|
-
.
|
|
92
|
+
|
|
93
|
+
.header-left {
|
|
93
94
|
display: flex;
|
|
94
95
|
align-items: center;
|
|
95
|
-
gap:
|
|
96
|
+
gap: 10px;
|
|
97
|
+
position: relative;
|
|
96
98
|
}
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
|
|
100
|
+
.header-center {
|
|
101
|
+
flex: 1;
|
|
102
|
+
display: flex;
|
|
103
|
+
justify-content: center;
|
|
101
104
|
}
|
|
102
|
-
|
|
103
|
-
.
|
|
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:
|
|
204
|
+
background: transparent;
|
|
116
205
|
color: #ccc;
|
|
117
|
-
border: 1px solid #
|
|
118
|
-
padding: 4px
|
|
206
|
+
border: 1px solid #444;
|
|
207
|
+
padding: 4px 12px;
|
|
119
208
|
border-radius: 4px;
|
|
120
209
|
cursor: pointer;
|
|
121
|
-
font-size: 0.
|
|
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: #
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
background
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
198
|
-
|
|
274
|
+
font-size: 0.9em;
|
|
275
|
+
text-decoration: none;
|
|
199
276
|
transition: all 0.2s ease;
|
|
200
277
|
}
|
|
201
278
|
|
|
202
|
-
.
|
|
203
|
-
background:
|
|
204
|
-
|
|
279
|
+
.header-btn:hover {
|
|
280
|
+
background: #3a3a3a;
|
|
281
|
+
border-color: #667eea;
|
|
205
282
|
}
|
|
206
283
|
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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="
|
|
278
|
-
<
|
|
279
|
-
<
|
|
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
|
-
|
|
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:
|
|
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;">🚀
|
|
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
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
320
|
-
<
|
|
321
|
-
|
|
322
|
-
<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
<
|
|
328
|
-
|
|
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
|
-
|
|
332
|
-
|
|
333
|
-
<
|
|
334
|
-
|
|
335
|
-
<li
|
|
336
|
-
<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
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
package/public/app/terminal.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
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
|
|
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
|