shell-mirror 1.5.129 → 1.5.131
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 +183 -1
- package/public/app/terminal.js +167 -8
- package/public/images/logo.png +0 -0
- package/public/images/logo_120.png +0 -0
- package/public/index.html +232 -208
package/package.json
CHANGED
package/public/app/terminal.html
CHANGED
|
@@ -370,6 +370,151 @@
|
|
|
370
370
|
white-space: nowrap;
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
|
+
|
|
374
|
+
/* ========================================
|
|
375
|
+
Floating Buttons - Mobile CLI Shortcuts
|
|
376
|
+
======================================== */
|
|
377
|
+
.floating-buttons {
|
|
378
|
+
position: fixed;
|
|
379
|
+
bottom: 20px;
|
|
380
|
+
left: 50%;
|
|
381
|
+
transform: translateX(-50%);
|
|
382
|
+
z-index: 1000;
|
|
383
|
+
display: flex;
|
|
384
|
+
align-items: center;
|
|
385
|
+
gap: 0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* Toggle button (collapse/expand) */
|
|
389
|
+
.fab-toggle {
|
|
390
|
+
width: 40px;
|
|
391
|
+
height: 40px;
|
|
392
|
+
border-radius: 50%;
|
|
393
|
+
background: rgba(20, 21, 25, 0.95);
|
|
394
|
+
backdrop-filter: blur(10px);
|
|
395
|
+
-webkit-backdrop-filter: blur(10px);
|
|
396
|
+
border: 1px solid #2a2b30;
|
|
397
|
+
color: #fff;
|
|
398
|
+
font-size: 18px;
|
|
399
|
+
cursor: pointer;
|
|
400
|
+
flex-shrink: 0;
|
|
401
|
+
margin-right: 4px;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.fab-toggle:active {
|
|
405
|
+
background: #22232a;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/* Scroll indicators */
|
|
409
|
+
.fab-scroll {
|
|
410
|
+
width: 28px;
|
|
411
|
+
height: 48px;
|
|
412
|
+
background: rgba(20, 21, 25, 0.9);
|
|
413
|
+
border: none;
|
|
414
|
+
color: #8a8f98;
|
|
415
|
+
font-size: 22px;
|
|
416
|
+
font-weight: 300;
|
|
417
|
+
cursor: pointer;
|
|
418
|
+
flex-shrink: 0;
|
|
419
|
+
opacity: 0.8;
|
|
420
|
+
transition: opacity 0.15s;
|
|
421
|
+
display: flex;
|
|
422
|
+
align-items: center;
|
|
423
|
+
justify-content: center;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.fab-scroll:active { opacity: 1; background: #22232a; }
|
|
427
|
+
.fab-scroll.hidden { opacity: 0; pointer-events: none; width: 0; }
|
|
428
|
+
|
|
429
|
+
.fab-scroll-left {
|
|
430
|
+
border-radius: 10px 0 0 10px;
|
|
431
|
+
border: 1px solid #2a2b30;
|
|
432
|
+
border-right: none;
|
|
433
|
+
}
|
|
434
|
+
.fab-scroll-right {
|
|
435
|
+
border-radius: 0 10px 10px 0;
|
|
436
|
+
border: 1px solid #2a2b30;
|
|
437
|
+
border-left: none;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* Scrollable button strip */
|
|
441
|
+
.fab-strip {
|
|
442
|
+
display: flex;
|
|
443
|
+
gap: 6px;
|
|
444
|
+
overflow-x: auto;
|
|
445
|
+
scroll-snap-type: x mandatory;
|
|
446
|
+
scroll-behavior: smooth;
|
|
447
|
+
-webkit-overflow-scrolling: touch;
|
|
448
|
+
padding: 6px 10px;
|
|
449
|
+
background: rgba(20, 21, 25, 0.95);
|
|
450
|
+
backdrop-filter: blur(10px);
|
|
451
|
+
-webkit-backdrop-filter: blur(10px);
|
|
452
|
+
border-top: 1px solid #2a2b30;
|
|
453
|
+
border-bottom: 1px solid #2a2b30;
|
|
454
|
+
max-width: calc(100vw - 130px);
|
|
455
|
+
scrollbar-width: none;
|
|
456
|
+
transition: max-width 0.2s, opacity 0.2s, padding 0.2s;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.fab-strip::-webkit-scrollbar { display: none; }
|
|
460
|
+
|
|
461
|
+
/* Collapsed state */
|
|
462
|
+
.floating-buttons.collapsed .fab-strip,
|
|
463
|
+
.floating-buttons.collapsed .fab-scroll {
|
|
464
|
+
max-width: 0;
|
|
465
|
+
width: 0;
|
|
466
|
+
padding: 0;
|
|
467
|
+
opacity: 0;
|
|
468
|
+
overflow: hidden;
|
|
469
|
+
border: none;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* Individual buttons */
|
|
473
|
+
.fab-btn {
|
|
474
|
+
flex-shrink: 0;
|
|
475
|
+
min-width: 48px;
|
|
476
|
+
height: 44px;
|
|
477
|
+
padding: 0 12px;
|
|
478
|
+
border-radius: 8px;
|
|
479
|
+
background: #1a1b20;
|
|
480
|
+
color: #fff;
|
|
481
|
+
border: 1px solid #2a2b30;
|
|
482
|
+
font-size: 13px;
|
|
483
|
+
font-weight: 600;
|
|
484
|
+
scroll-snap-align: center;
|
|
485
|
+
white-space: nowrap;
|
|
486
|
+
cursor: pointer;
|
|
487
|
+
transition: background 0.1s;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.fab-btn:active { background: #22232a; }
|
|
491
|
+
|
|
492
|
+
/* Highlight most critical button (Mode switcher) */
|
|
493
|
+
.fab-btn.fab-primary {
|
|
494
|
+
background: #5d5fef;
|
|
495
|
+
border-color: #5d5fef;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.fab-btn.fab-primary:active {
|
|
499
|
+
background: #4a4cd6;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* Desktop: hide floating buttons */
|
|
503
|
+
@media (min-width: 1025px) {
|
|
504
|
+
.floating-buttons { display: none; }
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/* Small phones: adjust sizing */
|
|
508
|
+
@media (max-width: 375px) {
|
|
509
|
+
.fab-btn {
|
|
510
|
+
min-width: 44px;
|
|
511
|
+
padding: 0 10px;
|
|
512
|
+
font-size: 12px;
|
|
513
|
+
}
|
|
514
|
+
.fab-strip {
|
|
515
|
+
max-width: calc(100vw - 110px);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
373
518
|
</style>
|
|
374
519
|
</head>
|
|
375
520
|
<body>
|
|
@@ -400,7 +545,44 @@
|
|
|
400
545
|
</div>
|
|
401
546
|
<div id="terminal"></div>
|
|
402
547
|
</div>
|
|
403
|
-
|
|
548
|
+
|
|
549
|
+
<!-- Floating Buttons - Mobile CLI Shortcuts -->
|
|
550
|
+
<div id="floating-buttons" class="floating-buttons">
|
|
551
|
+
<!-- Toggle button (collapse/expand) -->
|
|
552
|
+
<button class="fab-toggle" id="fabToggle" aria-label="Toggle keyboard shortcuts">
|
|
553
|
+
<span class="fab-toggle-icon">⌨</span>
|
|
554
|
+
</button>
|
|
555
|
+
|
|
556
|
+
<!-- Left scroll indicator -->
|
|
557
|
+
<button class="fab-scroll fab-scroll-left hidden" id="fabScrollLeft" aria-label="Scroll left">
|
|
558
|
+
<span>‹</span>
|
|
559
|
+
</button>
|
|
560
|
+
|
|
561
|
+
<!-- Scrollable button strip -->
|
|
562
|
+
<div class="fab-strip" id="fabStrip">
|
|
563
|
+
<!-- Control group (scroll left to reveal) -->
|
|
564
|
+
<button class="fab-btn" data-keys="ctrl+l" title="Clear screen">^L</button>
|
|
565
|
+
<button class="fab-btn" data-keys="ctrl+d" title="EOF/Exit">^D</button>
|
|
566
|
+
<button class="fab-btn" data-keys="ctrl+c" title="Interrupt">^C</button>
|
|
567
|
+
|
|
568
|
+
<!-- Primary group (default visible - AI CLI essentials) -->
|
|
569
|
+
<button class="fab-btn fab-primary" data-keys="shift+tab" title="Mode: Normal → Auto → Plan">⇧Tab</button>
|
|
570
|
+
<button class="fab-btn" data-keys="tab" title="Autocomplete / Thinking">Tab</button>
|
|
571
|
+
<button class="fab-btn" data-keys="up" data-repeat="true" title="History up">↑</button>
|
|
572
|
+
<button class="fab-btn" data-keys="down" data-repeat="true" title="History down">↓</button>
|
|
573
|
+
<button class="fab-btn" data-keys="escape" title="Cancel / Rewind (2x)">Esc</button>
|
|
574
|
+
|
|
575
|
+
<!-- Navigation group (scroll right to reveal) -->
|
|
576
|
+
<button class="fab-btn" data-keys="left" title="Cursor left">←</button>
|
|
577
|
+
<button class="fab-btn" data-keys="right" title="Cursor right">→</button>
|
|
578
|
+
</div>
|
|
579
|
+
|
|
580
|
+
<!-- Right scroll indicator -->
|
|
581
|
+
<button class="fab-scroll fab-scroll-right" id="fabScrollRight" aria-label="Scroll right">
|
|
582
|
+
<span>›</span>
|
|
583
|
+
</button>
|
|
584
|
+
</div>
|
|
585
|
+
|
|
404
586
|
<!-- Help Modal (Dark Kraken Style) -->
|
|
405
587
|
<div id="help-modal" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.85); align-items: center; justify-content: center; z-index: 20000;">
|
|
406
588
|
<div style="background: #141519; border-radius: 8px; max-width: 500px; width: 90%; max-height: 80vh; overflow: hidden; border: 1px solid #2a2b30; box-shadow: 0 8px 32px rgba(0,0,0,0.5);">
|
package/public/app/terminal.js
CHANGED
|
@@ -1388,19 +1388,19 @@ function saveSessionToLocalStorage(agentId, sessionInfo) {
|
|
|
1388
1388
|
console.log('[CLIENT] 🔍 DEBUG: Saving session to localStorage');
|
|
1389
1389
|
console.log('[CLIENT] 🔍 DEBUG: AgentID:', agentId);
|
|
1390
1390
|
console.log('[CLIENT] 🔍 DEBUG: SessionInfo:', sessionInfo);
|
|
1391
|
-
|
|
1391
|
+
|
|
1392
1392
|
const storedSessions = localStorage.getItem('shell-mirror-sessions');
|
|
1393
1393
|
console.log('[CLIENT] 🔍 DEBUG: Current stored sessions:', storedSessions);
|
|
1394
|
-
|
|
1394
|
+
|
|
1395
1395
|
let sessionData = storedSessions ? JSON.parse(storedSessions) : {};
|
|
1396
|
-
|
|
1396
|
+
|
|
1397
1397
|
if (!sessionData[agentId]) {
|
|
1398
1398
|
sessionData[agentId] = [];
|
|
1399
1399
|
}
|
|
1400
|
-
|
|
1400
|
+
|
|
1401
1401
|
// Remove existing session with same ID
|
|
1402
1402
|
sessionData[agentId] = sessionData[agentId].filter(s => s.id !== sessionInfo.id);
|
|
1403
|
-
|
|
1403
|
+
|
|
1404
1404
|
// Add updated session info
|
|
1405
1405
|
const sessionToStore = {
|
|
1406
1406
|
id: sessionInfo.id,
|
|
@@ -1409,9 +1409,9 @@ function saveSessionToLocalStorage(agentId, sessionInfo) {
|
|
|
1409
1409
|
createdAt: sessionInfo.createdAt || Date.now(),
|
|
1410
1410
|
status: 'active'
|
|
1411
1411
|
};
|
|
1412
|
-
|
|
1412
|
+
|
|
1413
1413
|
sessionData[agentId].push(sessionToStore);
|
|
1414
|
-
|
|
1414
|
+
|
|
1415
1415
|
localStorage.setItem('shell-mirror-sessions', JSON.stringify(sessionData));
|
|
1416
1416
|
console.log('[CLIENT] 💾 Session saved to storage:', sessionToStore);
|
|
1417
1417
|
|
|
@@ -1431,4 +1431,163 @@ function saveSessionToLocalStorage(agentId, sessionInfo) {
|
|
|
1431
1431
|
} catch (error) {
|
|
1432
1432
|
console.error('[CLIENT] ❌ Error saving session to storage:', error);
|
|
1433
1433
|
}
|
|
1434
|
-
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// ========================================
|
|
1437
|
+
// Floating Buttons - Mobile CLI Shortcuts
|
|
1438
|
+
// ========================================
|
|
1439
|
+
|
|
1440
|
+
const fabKeyMap = {
|
|
1441
|
+
'shift+tab': '\x1b[Z', // Shift+Tab - MODE SWITCHING (most critical!)
|
|
1442
|
+
'tab': '\t', // Tab - autocomplete + thinking toggle
|
|
1443
|
+
'escape': '\x1b', // Esc - cancel (double = rewind)
|
|
1444
|
+
'up': '\x1b[A', // ↑ - history up
|
|
1445
|
+
'down': '\x1b[B', // ↓ - history down
|
|
1446
|
+
'left': '\x1b[D', // ← - cursor left
|
|
1447
|
+
'right': '\x1b[C', // → - cursor right
|
|
1448
|
+
'ctrl+c': '\x03', // ^C - interrupt
|
|
1449
|
+
'ctrl+d': '\x04', // ^D - EOF/exit
|
|
1450
|
+
'ctrl+l': '\x0c', // ^L - clear screen
|
|
1451
|
+
};
|
|
1452
|
+
|
|
1453
|
+
function initFloatingButtons() {
|
|
1454
|
+
const container = document.getElementById('floating-buttons');
|
|
1455
|
+
const toggle = document.getElementById('fabToggle');
|
|
1456
|
+
const strip = document.getElementById('fabStrip');
|
|
1457
|
+
const scrollLeft = document.getElementById('fabScrollLeft');
|
|
1458
|
+
const scrollRight = document.getElementById('fabScrollRight');
|
|
1459
|
+
|
|
1460
|
+
if (!container || !toggle || !strip) {
|
|
1461
|
+
console.log('[CLIENT] ⌨️ Floating buttons not found in DOM');
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
console.log('[CLIENT] ⌨️ Initializing floating buttons for mobile CLI shortcuts');
|
|
1466
|
+
|
|
1467
|
+
// Toggle collapse/expand
|
|
1468
|
+
toggle.addEventListener('click', () => {
|
|
1469
|
+
container.classList.toggle('collapsed');
|
|
1470
|
+
localStorage.setItem('fab-collapsed', container.classList.contains('collapsed'));
|
|
1471
|
+
});
|
|
1472
|
+
|
|
1473
|
+
// Restore saved collapsed state
|
|
1474
|
+
if (localStorage.getItem('fab-collapsed') === 'true') {
|
|
1475
|
+
container.classList.add('collapsed');
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// Scroll indicator click handlers
|
|
1479
|
+
const scrollAmount = 150; // pixels per click
|
|
1480
|
+
|
|
1481
|
+
if (scrollLeft) {
|
|
1482
|
+
scrollLeft.addEventListener('click', () => {
|
|
1483
|
+
strip.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
if (scrollRight) {
|
|
1488
|
+
scrollRight.addEventListener('click', () => {
|
|
1489
|
+
strip.scrollBy({ left: scrollAmount, behavior: 'smooth' });
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// Update scroll indicator visibility based on scroll position
|
|
1494
|
+
function updateScrollIndicators() {
|
|
1495
|
+
if (!scrollLeft || !scrollRight) return;
|
|
1496
|
+
|
|
1497
|
+
const atStart = strip.scrollLeft <= 5;
|
|
1498
|
+
const atEnd = strip.scrollLeft >= strip.scrollWidth - strip.clientWidth - 5;
|
|
1499
|
+
|
|
1500
|
+
scrollLeft.classList.toggle('hidden', atStart);
|
|
1501
|
+
scrollRight.classList.toggle('hidden', atEnd);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
strip.addEventListener('scroll', updateScrollIndicators);
|
|
1505
|
+
|
|
1506
|
+
// Button click handlers - send key sequences to terminal
|
|
1507
|
+
document.querySelectorAll('.fab-btn').forEach(btn => {
|
|
1508
|
+
btn.addEventListener('click', (e) => {
|
|
1509
|
+
e.preventDefault();
|
|
1510
|
+
const keys = btn.dataset.keys;
|
|
1511
|
+
if (keys && fabKeyMap[keys]) {
|
|
1512
|
+
// Send the key sequence through the terminal input handler
|
|
1513
|
+
sendFabKey(fabKeyMap[keys]);
|
|
1514
|
+
term.focus();
|
|
1515
|
+
}
|
|
1516
|
+
});
|
|
1517
|
+
});
|
|
1518
|
+
|
|
1519
|
+
// Long-press repeat for arrow keys
|
|
1520
|
+
initFabLongPress();
|
|
1521
|
+
|
|
1522
|
+
// Scroll to show primary buttons (⇧Tab visible on left)
|
|
1523
|
+
setTimeout(() => {
|
|
1524
|
+
const modeBtn = strip.querySelector('[data-keys="shift+tab"]');
|
|
1525
|
+
if (modeBtn) {
|
|
1526
|
+
strip.scrollLeft = modeBtn.offsetLeft - 10;
|
|
1527
|
+
}
|
|
1528
|
+
updateScrollIndicators();
|
|
1529
|
+
}, 100);
|
|
1530
|
+
|
|
1531
|
+
console.log('[CLIENT] ⌨️ Floating buttons initialized');
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// Send key sequence through the appropriate connection
|
|
1535
|
+
function sendFabKey(keySequence) {
|
|
1536
|
+
// Use the same logic as term.onData - send through WebRTC or direct WS
|
|
1537
|
+
if (dataChannel && dataChannel.readyState === 'open') {
|
|
1538
|
+
dataChannel.send(JSON.stringify({ type: 'input', data: keySequence }));
|
|
1539
|
+
} else if (ws && ws.readyState === WebSocket.OPEN && currentSession) {
|
|
1540
|
+
ws.send(JSON.stringify({
|
|
1541
|
+
type: 'input',
|
|
1542
|
+
sessionId: currentSession.id,
|
|
1543
|
+
data: keySequence
|
|
1544
|
+
}));
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// Long-press support for arrow buttons (↑/↓)
|
|
1549
|
+
function initFabLongPress() {
|
|
1550
|
+
document.querySelectorAll('.fab-btn[data-repeat="true"]').forEach(btn => {
|
|
1551
|
+
let interval = null;
|
|
1552
|
+
let timeout = null;
|
|
1553
|
+
|
|
1554
|
+
const startRepeat = () => {
|
|
1555
|
+
const keys = btn.dataset.keys;
|
|
1556
|
+
if (!keys || !fabKeyMap[keys]) return;
|
|
1557
|
+
|
|
1558
|
+
// First key immediately
|
|
1559
|
+
sendFabKey(fabKeyMap[keys]);
|
|
1560
|
+
term.focus();
|
|
1561
|
+
|
|
1562
|
+
// Then repeat after delay
|
|
1563
|
+
timeout = setTimeout(() => {
|
|
1564
|
+
interval = setInterval(() => {
|
|
1565
|
+
sendFabKey(fabKeyMap[keys]);
|
|
1566
|
+
}, 100); // Repeat every 100ms
|
|
1567
|
+
}, 300); // Start repeating after 300ms hold
|
|
1568
|
+
};
|
|
1569
|
+
|
|
1570
|
+
const stopRepeat = () => {
|
|
1571
|
+
if (timeout) clearTimeout(timeout);
|
|
1572
|
+
if (interval) clearInterval(interval);
|
|
1573
|
+
timeout = null;
|
|
1574
|
+
interval = null;
|
|
1575
|
+
};
|
|
1576
|
+
|
|
1577
|
+
// Touch events for mobile
|
|
1578
|
+
btn.addEventListener('touchstart', (e) => {
|
|
1579
|
+
e.preventDefault();
|
|
1580
|
+
startRepeat();
|
|
1581
|
+
});
|
|
1582
|
+
btn.addEventListener('touchend', stopRepeat);
|
|
1583
|
+
btn.addEventListener('touchcancel', stopRepeat);
|
|
1584
|
+
|
|
1585
|
+
// Mouse events for testing on desktop
|
|
1586
|
+
btn.addEventListener('mousedown', startRepeat);
|
|
1587
|
+
btn.addEventListener('mouseup', stopRepeat);
|
|
1588
|
+
btn.addEventListener('mouseleave', stopRepeat);
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// Initialize floating buttons when DOM is ready
|
|
1593
|
+
document.addEventListener('DOMContentLoaded', initFloatingButtons);
|
|
Binary file
|
|
Binary file
|
package/public/index.html
CHANGED
|
@@ -53,6 +53,20 @@
|
|
|
53
53
|
</script>
|
|
54
54
|
|
|
55
55
|
<style>
|
|
56
|
+
:root {
|
|
57
|
+
--bg-primary: #0a0b0d;
|
|
58
|
+
--bg-secondary: #141519;
|
|
59
|
+
--bg-tertiary: #1a1b20;
|
|
60
|
+
--bg-hover: #22232a;
|
|
61
|
+
--text-primary: #ffffff;
|
|
62
|
+
--text-secondary: #8a8f98;
|
|
63
|
+
--text-muted: #5a5f6a;
|
|
64
|
+
--accent: #5d5fef;
|
|
65
|
+
--accent-hover: #4a4cd6;
|
|
66
|
+
--success: #00c853;
|
|
67
|
+
--border: #2a2b30;
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
* {
|
|
57
71
|
margin: 0;
|
|
58
72
|
padding: 0;
|
|
@@ -62,8 +76,8 @@
|
|
|
62
76
|
body {
|
|
63
77
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
64
78
|
line-height: 1.6;
|
|
65
|
-
color:
|
|
66
|
-
background:
|
|
79
|
+
color: var(--text-primary);
|
|
80
|
+
background: var(--bg-primary);
|
|
67
81
|
min-height: 100vh;
|
|
68
82
|
}
|
|
69
83
|
|
|
@@ -75,9 +89,11 @@
|
|
|
75
89
|
|
|
76
90
|
/* Header */
|
|
77
91
|
header {
|
|
78
|
-
padding:
|
|
92
|
+
padding: 16px 0;
|
|
79
93
|
position: relative;
|
|
80
94
|
z-index: 100;
|
|
95
|
+
background: var(--bg-secondary);
|
|
96
|
+
border-bottom: 1px solid var(--border);
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
nav {
|
|
@@ -87,46 +103,44 @@
|
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
.logo {
|
|
90
|
-
font-size:
|
|
91
|
-
font-weight:
|
|
92
|
-
color:
|
|
106
|
+
font-size: 1.2rem;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
color: var(--text-primary);
|
|
93
109
|
}
|
|
94
110
|
|
|
95
111
|
.cta-button {
|
|
96
|
-
background:
|
|
112
|
+
background: var(--accent);
|
|
97
113
|
color: white;
|
|
98
|
-
padding:
|
|
114
|
+
padding: 10px 20px;
|
|
99
115
|
text-decoration: none;
|
|
100
|
-
border-radius:
|
|
116
|
+
border-radius: 6px;
|
|
101
117
|
font-weight: 500;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
transition: all 0.3s ease;
|
|
118
|
+
border: none;
|
|
119
|
+
transition: all 0.15s ease;
|
|
105
120
|
}
|
|
106
121
|
|
|
107
122
|
.cta-button:hover {
|
|
108
|
-
background:
|
|
109
|
-
transform: translateY(-2px);
|
|
123
|
+
background: var(--accent-hover);
|
|
110
124
|
}
|
|
111
125
|
|
|
112
126
|
/* Hero Section */
|
|
113
127
|
.hero {
|
|
114
128
|
text-align: center;
|
|
115
129
|
padding: 60px 0 80px;
|
|
116
|
-
color:
|
|
130
|
+
color: var(--text-primary);
|
|
117
131
|
}
|
|
118
132
|
|
|
119
133
|
.hero h1 {
|
|
120
|
-
font-size: clamp(
|
|
121
|
-
font-weight:
|
|
122
|
-
margin-bottom:
|
|
134
|
+
font-size: clamp(2rem, 4vw, 3rem);
|
|
135
|
+
font-weight: 600;
|
|
136
|
+
margin-bottom: 16px;
|
|
123
137
|
line-height: 1.2;
|
|
124
138
|
}
|
|
125
139
|
|
|
126
140
|
.hero p {
|
|
127
|
-
font-size: clamp(
|
|
141
|
+
font-size: clamp(1rem, 1.5vw, 1.1rem);
|
|
128
142
|
margin-bottom: 40px;
|
|
129
|
-
|
|
143
|
+
color: var(--text-secondary);
|
|
130
144
|
max-width: 600px;
|
|
131
145
|
margin-left: auto;
|
|
132
146
|
margin-right: auto;
|
|
@@ -134,45 +148,43 @@
|
|
|
134
148
|
|
|
135
149
|
.hero-buttons {
|
|
136
150
|
display: flex;
|
|
137
|
-
gap:
|
|
151
|
+
gap: 16px;
|
|
138
152
|
justify-content: center;
|
|
139
153
|
flex-wrap: wrap;
|
|
140
154
|
margin-bottom: 60px;
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
.btn-primary {
|
|
144
|
-
background:
|
|
158
|
+
background: var(--accent);
|
|
145
159
|
color: white;
|
|
146
|
-
padding:
|
|
160
|
+
padding: 14px 28px;
|
|
147
161
|
text-decoration: none;
|
|
148
|
-
border-radius:
|
|
149
|
-
font-weight:
|
|
150
|
-
font-size:
|
|
151
|
-
transition: all 0.
|
|
152
|
-
|
|
162
|
+
border-radius: 6px;
|
|
163
|
+
font-weight: 500;
|
|
164
|
+
font-size: 1rem;
|
|
165
|
+
transition: all 0.15s ease;
|
|
166
|
+
border: none;
|
|
153
167
|
}
|
|
154
168
|
|
|
155
169
|
.btn-primary:hover {
|
|
156
|
-
background:
|
|
157
|
-
transform: translateY(-2px);
|
|
158
|
-
box-shadow: 0 6px 20px rgba(66, 133, 244, 0.4);
|
|
170
|
+
background: var(--accent-hover);
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
.btn-secondary {
|
|
162
174
|
background: transparent;
|
|
163
|
-
color:
|
|
164
|
-
padding:
|
|
175
|
+
color: var(--text-primary);
|
|
176
|
+
padding: 14px 28px;
|
|
165
177
|
text-decoration: none;
|
|
166
|
-
border-radius:
|
|
167
|
-
font-weight:
|
|
168
|
-
font-size:
|
|
169
|
-
border:
|
|
170
|
-
transition: all 0.
|
|
178
|
+
border-radius: 6px;
|
|
179
|
+
font-weight: 500;
|
|
180
|
+
font-size: 1rem;
|
|
181
|
+
border: 1px solid var(--border);
|
|
182
|
+
transition: all 0.15s ease;
|
|
171
183
|
}
|
|
172
184
|
|
|
173
185
|
.btn-secondary:hover {
|
|
174
|
-
background:
|
|
175
|
-
color:
|
|
186
|
+
background: var(--bg-hover);
|
|
187
|
+
border-color: var(--text-muted);
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
/* Setup Steps */
|
|
@@ -181,42 +193,45 @@
|
|
|
181
193
|
max-width: 600px;
|
|
182
194
|
display: flex;
|
|
183
195
|
flex-direction: column;
|
|
184
|
-
gap:
|
|
196
|
+
gap: 16px;
|
|
185
197
|
}
|
|
186
198
|
|
|
187
199
|
.setup-step {
|
|
188
200
|
display: flex;
|
|
189
201
|
align-items: center;
|
|
190
|
-
gap:
|
|
202
|
+
gap: 16px;
|
|
191
203
|
}
|
|
192
204
|
|
|
193
205
|
.step-number {
|
|
194
|
-
font-size:
|
|
195
|
-
font-weight:
|
|
196
|
-
color:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
206
|
+
font-size: 1rem;
|
|
207
|
+
font-weight: 600;
|
|
208
|
+
color: var(--text-muted);
|
|
209
|
+
min-width: 32px;
|
|
210
|
+
height: 32px;
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
justify-content: center;
|
|
214
|
+
background: var(--bg-tertiary);
|
|
215
|
+
border-radius: 50%;
|
|
200
216
|
}
|
|
201
217
|
|
|
202
218
|
/* Installation Code */
|
|
203
219
|
.install-code {
|
|
204
|
-
background:
|
|
205
|
-
padding: 20px;
|
|
206
|
-
border-radius:
|
|
207
|
-
|
|
208
|
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
220
|
+
background: var(--bg-tertiary);
|
|
221
|
+
padding: 16px 20px;
|
|
222
|
+
border-radius: 6px;
|
|
223
|
+
border: 1px solid var(--border);
|
|
209
224
|
position: relative;
|
|
210
225
|
flex: 1;
|
|
211
|
-
height:
|
|
226
|
+
height: 56px;
|
|
212
227
|
display: flex;
|
|
213
228
|
align-items: center;
|
|
214
229
|
}
|
|
215
230
|
|
|
216
231
|
.install-code pre {
|
|
217
|
-
color:
|
|
232
|
+
color: var(--success);
|
|
218
233
|
font-family: 'Monaco', 'Menlo', monospace;
|
|
219
|
-
font-size:
|
|
234
|
+
font-size: 0.95rem;
|
|
220
235
|
margin: 0;
|
|
221
236
|
padding-right: 40px;
|
|
222
237
|
flex: 1;
|
|
@@ -224,21 +239,23 @@
|
|
|
224
239
|
|
|
225
240
|
.copy-btn {
|
|
226
241
|
position: absolute;
|
|
227
|
-
right:
|
|
242
|
+
right: 12px;
|
|
228
243
|
top: 50%;
|
|
229
244
|
transform: translateY(-50%);
|
|
230
|
-
background:
|
|
231
|
-
border: 1px solid
|
|
232
|
-
border-radius:
|
|
233
|
-
padding:
|
|
234
|
-
color:
|
|
245
|
+
background: var(--bg-hover);
|
|
246
|
+
border: 1px solid var(--border);
|
|
247
|
+
border-radius: 4px;
|
|
248
|
+
padding: 6px 10px;
|
|
249
|
+
color: var(--text-secondary);
|
|
235
250
|
cursor: pointer;
|
|
236
|
-
transition: all 0.
|
|
251
|
+
transition: all 0.15s ease;
|
|
252
|
+
font-size: 0.75rem;
|
|
237
253
|
}
|
|
238
254
|
|
|
239
255
|
.copy-btn:hover {
|
|
240
|
-
background:
|
|
241
|
-
|
|
256
|
+
background: var(--accent);
|
|
257
|
+
border-color: var(--accent);
|
|
258
|
+
color: white;
|
|
242
259
|
}
|
|
243
260
|
|
|
244
261
|
.copy-btn:active {
|
|
@@ -253,31 +270,27 @@
|
|
|
253
270
|
.btn-google {
|
|
254
271
|
background: white;
|
|
255
272
|
color: #3c4043;
|
|
256
|
-
padding: 20px
|
|
257
|
-
border:
|
|
258
|
-
border-radius:
|
|
273
|
+
padding: 16px 20px;
|
|
274
|
+
border: none;
|
|
275
|
+
border-radius: 6px;
|
|
259
276
|
font-weight: 500;
|
|
260
|
-
font-size:
|
|
277
|
+
font-size: 0.95rem;
|
|
261
278
|
display: flex;
|
|
262
279
|
align-items: center;
|
|
263
280
|
justify-content: center;
|
|
264
|
-
gap:
|
|
265
|
-
transition: all 0.
|
|
281
|
+
gap: 10px;
|
|
282
|
+
transition: all 0.15s ease;
|
|
266
283
|
cursor: pointer;
|
|
267
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
268
284
|
flex: 1;
|
|
269
|
-
height:
|
|
285
|
+
height: 56px;
|
|
270
286
|
}
|
|
271
287
|
|
|
272
288
|
.btn-google:hover {
|
|
273
|
-
background: #
|
|
274
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
275
|
-
/* transform: translateY(-1px); */
|
|
289
|
+
background: #f0f0f0;
|
|
276
290
|
}
|
|
277
291
|
|
|
278
292
|
.btn-google:active {
|
|
279
|
-
transform:
|
|
280
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
293
|
+
transform: scale(0.98);
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
/* Installation Modal */
|
|
@@ -299,9 +312,10 @@
|
|
|
299
312
|
}
|
|
300
313
|
|
|
301
314
|
.install-modal-content {
|
|
302
|
-
background:
|
|
303
|
-
padding:
|
|
304
|
-
border-radius:
|
|
315
|
+
background: var(--bg-secondary);
|
|
316
|
+
padding: 24px;
|
|
317
|
+
border-radius: 8px;
|
|
318
|
+
border: 1px solid var(--border);
|
|
305
319
|
max-width: 500px;
|
|
306
320
|
margin: 20px;
|
|
307
321
|
text-align: center;
|
|
@@ -309,23 +323,22 @@
|
|
|
309
323
|
}
|
|
310
324
|
|
|
311
325
|
.install-modal-content h3 {
|
|
312
|
-
color:
|
|
313
|
-
margin-bottom:
|
|
326
|
+
color: var(--text-primary);
|
|
327
|
+
margin-bottom: 16px;
|
|
314
328
|
}
|
|
315
329
|
|
|
316
330
|
.install-modal-content p {
|
|
317
|
-
color:
|
|
318
|
-
margin-bottom:
|
|
331
|
+
color: var(--text-secondary);
|
|
332
|
+
margin-bottom: 16px;
|
|
319
333
|
}
|
|
320
334
|
|
|
321
335
|
.install-modal-content .install-code {
|
|
322
|
-
background:
|
|
323
|
-
|
|
324
|
-
margin: 20px 0;
|
|
336
|
+
background: var(--bg-tertiary);
|
|
337
|
+
margin: 16px 0;
|
|
325
338
|
}
|
|
326
339
|
|
|
327
340
|
.install-modal-content .install-code pre {
|
|
328
|
-
color:
|
|
341
|
+
color: var(--success);
|
|
329
342
|
}
|
|
330
343
|
|
|
331
344
|
.close-modal {
|
|
@@ -336,65 +349,70 @@
|
|
|
336
349
|
border: none;
|
|
337
350
|
font-size: 24px;
|
|
338
351
|
cursor: pointer;
|
|
339
|
-
color:
|
|
352
|
+
color: var(--text-muted);
|
|
340
353
|
}
|
|
341
354
|
|
|
342
355
|
.close-modal:hover {
|
|
343
|
-
color:
|
|
356
|
+
color: var(--text-primary);
|
|
344
357
|
}
|
|
345
358
|
|
|
346
359
|
/* How It Works */
|
|
347
360
|
.how-it-works {
|
|
348
|
-
background:
|
|
361
|
+
background: var(--bg-secondary);
|
|
349
362
|
padding: 80px 0;
|
|
350
363
|
}
|
|
351
364
|
|
|
352
365
|
.section-title {
|
|
353
366
|
text-align: center;
|
|
354
|
-
font-size:
|
|
355
|
-
|
|
356
|
-
|
|
367
|
+
font-size: 1.75rem;
|
|
368
|
+
font-weight: 600;
|
|
369
|
+
margin-bottom: 48px;
|
|
370
|
+
color: var(--text-primary);
|
|
357
371
|
}
|
|
358
372
|
|
|
359
373
|
.steps {
|
|
360
374
|
display: grid;
|
|
361
375
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
362
|
-
gap:
|
|
363
|
-
margin-bottom:
|
|
376
|
+
gap: 32px;
|
|
377
|
+
margin-bottom: 48px;
|
|
364
378
|
}
|
|
365
379
|
|
|
366
380
|
.step {
|
|
367
381
|
text-align: center;
|
|
368
|
-
padding:
|
|
382
|
+
padding: 24px 16px;
|
|
369
383
|
}
|
|
370
384
|
|
|
371
385
|
.step-icon {
|
|
372
|
-
width:
|
|
373
|
-
height:
|
|
374
|
-
background:
|
|
386
|
+
width: 56px;
|
|
387
|
+
height: 56px;
|
|
388
|
+
background: var(--bg-tertiary);
|
|
389
|
+
border: 1px solid var(--border);
|
|
375
390
|
border-radius: 50%;
|
|
376
391
|
display: flex;
|
|
377
392
|
align-items: center;
|
|
378
393
|
justify-content: center;
|
|
379
|
-
margin: 0 auto
|
|
380
|
-
font-size:
|
|
381
|
-
|
|
394
|
+
margin: 0 auto 16px;
|
|
395
|
+
font-size: 1.25rem;
|
|
396
|
+
font-weight: 600;
|
|
397
|
+
color: var(--text-secondary);
|
|
382
398
|
}
|
|
383
399
|
|
|
384
400
|
.step h3 {
|
|
385
|
-
font-size: 1.
|
|
386
|
-
|
|
387
|
-
|
|
401
|
+
font-size: 1.1rem;
|
|
402
|
+
font-weight: 600;
|
|
403
|
+
margin-bottom: 12px;
|
|
404
|
+
color: var(--text-primary);
|
|
388
405
|
}
|
|
389
406
|
|
|
390
407
|
.step p {
|
|
391
|
-
color:
|
|
408
|
+
color: var(--text-secondary);
|
|
392
409
|
line-height: 1.6;
|
|
410
|
+
font-size: 0.95rem;
|
|
393
411
|
}
|
|
394
412
|
|
|
395
413
|
/* Security Section */
|
|
396
414
|
.security {
|
|
397
|
-
background:
|
|
415
|
+
background: var(--bg-tertiary);
|
|
398
416
|
padding: 80px 0;
|
|
399
417
|
}
|
|
400
418
|
|
|
@@ -402,102 +420,118 @@
|
|
|
402
420
|
display: flex;
|
|
403
421
|
align-items: center;
|
|
404
422
|
justify-content: center;
|
|
405
|
-
gap:
|
|
423
|
+
gap: 24px;
|
|
406
424
|
flex-wrap: wrap;
|
|
407
425
|
margin: 40px 0;
|
|
408
426
|
}
|
|
409
427
|
|
|
410
428
|
.security-step {
|
|
411
|
-
background:
|
|
429
|
+
background: var(--bg-secondary);
|
|
412
430
|
padding: 20px;
|
|
413
|
-
border-radius:
|
|
414
|
-
|
|
431
|
+
border-radius: 6px;
|
|
432
|
+
border: 1px solid var(--border);
|
|
415
433
|
text-align: center;
|
|
416
|
-
min-width:
|
|
434
|
+
min-width: 180px;
|
|
417
435
|
}
|
|
418
436
|
|
|
419
437
|
.security-step h4 {
|
|
420
|
-
color:
|
|
421
|
-
margin-bottom:
|
|
438
|
+
color: var(--accent);
|
|
439
|
+
margin-bottom: 8px;
|
|
440
|
+
font-size: 0.95rem;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.security-step p {
|
|
444
|
+
color: var(--text-secondary);
|
|
445
|
+
font-size: 0.85rem;
|
|
422
446
|
}
|
|
423
447
|
|
|
424
448
|
.arrow {
|
|
425
|
-
font-size:
|
|
426
|
-
color:
|
|
449
|
+
font-size: 1.5rem;
|
|
450
|
+
color: var(--text-muted);
|
|
427
451
|
}
|
|
428
452
|
|
|
429
453
|
/* Use Cases */
|
|
430
454
|
.use-cases {
|
|
431
455
|
padding: 80px 0;
|
|
432
|
-
background:
|
|
456
|
+
background: var(--bg-secondary);
|
|
433
457
|
}
|
|
434
458
|
|
|
435
459
|
.use-case-grid {
|
|
436
460
|
display: grid;
|
|
437
461
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
438
|
-
gap:
|
|
462
|
+
gap: 24px;
|
|
439
463
|
}
|
|
440
464
|
|
|
441
465
|
.use-case {
|
|
442
|
-
background:
|
|
443
|
-
padding:
|
|
444
|
-
border-radius:
|
|
445
|
-
border-left:
|
|
466
|
+
background: var(--bg-tertiary);
|
|
467
|
+
padding: 24px;
|
|
468
|
+
border-radius: 6px;
|
|
469
|
+
border-left: 3px solid var(--accent);
|
|
446
470
|
}
|
|
447
471
|
|
|
448
472
|
.use-case h3 {
|
|
449
|
-
color:
|
|
450
|
-
margin-bottom:
|
|
473
|
+
color: var(--text-primary);
|
|
474
|
+
margin-bottom: 12px;
|
|
475
|
+
font-size: 1rem;
|
|
476
|
+
font-weight: 600;
|
|
451
477
|
}
|
|
452
478
|
|
|
453
479
|
.use-case p {
|
|
454
|
-
color:
|
|
480
|
+
color: var(--text-secondary);
|
|
481
|
+
font-size: 0.95rem;
|
|
455
482
|
}
|
|
456
483
|
|
|
457
484
|
/* Footer CTA */
|
|
458
485
|
.footer-cta {
|
|
459
|
-
background:
|
|
486
|
+
background: var(--bg-primary);
|
|
487
|
+
border-top: 1px solid var(--border);
|
|
460
488
|
padding: 60px 0;
|
|
461
489
|
text-align: center;
|
|
462
|
-
color:
|
|
490
|
+
color: var(--text-primary);
|
|
463
491
|
}
|
|
464
492
|
|
|
465
493
|
.footer-cta h2 {
|
|
466
|
-
font-size:
|
|
467
|
-
|
|
494
|
+
font-size: 1.75rem;
|
|
495
|
+
font-weight: 600;
|
|
496
|
+
margin-bottom: 16px;
|
|
468
497
|
}
|
|
469
498
|
|
|
470
499
|
.footer-cta p {
|
|
471
|
-
font-size:
|
|
472
|
-
margin-bottom:
|
|
473
|
-
|
|
500
|
+
font-size: 1rem;
|
|
501
|
+
margin-bottom: 32px;
|
|
502
|
+
color: var(--text-secondary);
|
|
474
503
|
}
|
|
475
504
|
|
|
476
505
|
/* Responsive Design */
|
|
477
506
|
@media (max-width: 768px) {
|
|
478
507
|
.setup-steps {
|
|
479
|
-
max-width:
|
|
480
|
-
gap:
|
|
508
|
+
max-width: 95%;
|
|
509
|
+
gap: 12px;
|
|
481
510
|
}
|
|
482
511
|
|
|
483
512
|
.setup-step {
|
|
484
|
-
gap:
|
|
513
|
+
gap: 12px;
|
|
485
514
|
}
|
|
486
515
|
|
|
487
516
|
.step-number {
|
|
488
|
-
|
|
489
|
-
|
|
517
|
+
min-width: 28px;
|
|
518
|
+
height: 28px;
|
|
519
|
+
font-size: 0.85rem;
|
|
490
520
|
}
|
|
491
521
|
|
|
492
522
|
.install-code {
|
|
493
|
-
height:
|
|
494
|
-
padding:
|
|
523
|
+
height: 48px;
|
|
524
|
+
padding: 12px 16px;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.install-code pre {
|
|
528
|
+
font-size: 0.85rem;
|
|
495
529
|
}
|
|
496
530
|
|
|
497
531
|
.btn-google {
|
|
498
|
-
height:
|
|
499
|
-
padding:
|
|
500
|
-
font-size: 0.
|
|
532
|
+
height: 48px;
|
|
533
|
+
padding: 12px 16px;
|
|
534
|
+
font-size: 0.85rem;
|
|
501
535
|
}
|
|
502
536
|
|
|
503
537
|
.hero-buttons {
|
|
@@ -506,7 +540,7 @@
|
|
|
506
540
|
}
|
|
507
541
|
|
|
508
542
|
.btn-primary {
|
|
509
|
-
width:
|
|
543
|
+
width: 240px;
|
|
510
544
|
}
|
|
511
545
|
|
|
512
546
|
.security-flow {
|
|
@@ -520,22 +554,24 @@
|
|
|
520
554
|
.steps {
|
|
521
555
|
grid-template-columns: 1fr;
|
|
522
556
|
}
|
|
523
|
-
}
|
|
524
557
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
from {
|
|
528
|
-
opacity: 0;
|
|
529
|
-
transform: translateY(30px);
|
|
558
|
+
.section-title {
|
|
559
|
+
font-size: 1.5rem;
|
|
530
560
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
561
|
+
|
|
562
|
+
.hero h1 {
|
|
563
|
+
font-size: 1.75rem;
|
|
534
564
|
}
|
|
535
565
|
}
|
|
536
566
|
|
|
537
|
-
|
|
538
|
-
|
|
567
|
+
/* Subtle animations */
|
|
568
|
+
@keyframes fadeIn {
|
|
569
|
+
from { opacity: 0; }
|
|
570
|
+
to { opacity: 1; }
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.hero {
|
|
574
|
+
animation: fadeIn 0.4s ease-out;
|
|
539
575
|
}
|
|
540
576
|
</style>
|
|
541
577
|
</head>
|
|
@@ -554,8 +590,8 @@
|
|
|
554
590
|
<h1>Mirror your Mac terminal<br>to your phone</h1>
|
|
555
591
|
<p>Continue your Claude Code or Gemini CLI session on your phone or iPad while on the go.</p>
|
|
556
592
|
|
|
557
|
-
<p style="text-align: center; color:
|
|
558
|
-
|
|
593
|
+
<p style="text-align: center; color: var(--text-muted); font-size: 0.9rem; margin: 40px 0 24px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px;">
|
|
594
|
+
Quick Setup
|
|
559
595
|
</p>
|
|
560
596
|
|
|
561
597
|
<div class="setup-steps">
|
|
@@ -612,19 +648,19 @@
|
|
|
612
648
|
|
|
613
649
|
<div class="steps">
|
|
614
650
|
<div class="step">
|
|
615
|
-
<div class="step-icon"
|
|
651
|
+
<div class="step-icon">1</div>
|
|
616
652
|
<h3>Secure Login</h3>
|
|
617
653
|
<p>Sign in with your Google account. Your credentials are encrypted and secure.</p>
|
|
618
654
|
</div>
|
|
619
|
-
|
|
655
|
+
|
|
620
656
|
<div class="step">
|
|
621
|
-
<div class="step-icon"
|
|
657
|
+
<div class="step-icon">2</div>
|
|
622
658
|
<h3>Cloud Terminal</h3>
|
|
623
659
|
<p>Access a cloud-based terminal environment with all your favorite command-line tools pre-installed.</p>
|
|
624
660
|
</div>
|
|
625
|
-
|
|
661
|
+
|
|
626
662
|
<div class="step">
|
|
627
|
-
<div class="step-icon"
|
|
663
|
+
<div class="step-icon">3</div>
|
|
628
664
|
<h3>Any Device</h3>
|
|
629
665
|
<p>Use from your phone, tablet, or any web browser. Your terminal is always accessible.</p>
|
|
630
666
|
</div>
|
|
@@ -636,7 +672,7 @@
|
|
|
636
672
|
<section class="security" id="security">
|
|
637
673
|
<div class="container">
|
|
638
674
|
<h2 class="section-title">Secure & Reliable</h2>
|
|
639
|
-
<p style="text-align: center; margin-bottom: 40px; color:
|
|
675
|
+
<p style="text-align: center; margin-bottom: 40px; color: var(--text-secondary); font-size: 0.95rem;">
|
|
640
676
|
Enterprise-grade security with Google OAuth authentication.
|
|
641
677
|
</p>
|
|
642
678
|
|
|
@@ -658,10 +694,12 @@
|
|
|
658
694
|
</div>
|
|
659
695
|
|
|
660
696
|
<div style="text-align: center; margin-top: 40px;">
|
|
661
|
-
<p style="color:
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
697
|
+
<p style="color: var(--text-muted); font-size: 0.9rem; line-height: 1.8;">
|
|
698
|
+
Encrypted connections (HTTPS/WSS)<br>
|
|
699
|
+
Google-grade authentication<br>
|
|
700
|
+
Session-based security<br>
|
|
701
|
+
No local installation required
|
|
702
|
+
</p>
|
|
665
703
|
</div>
|
|
666
704
|
</div>
|
|
667
705
|
</section>
|
|
@@ -673,32 +711,32 @@
|
|
|
673
711
|
|
|
674
712
|
<div class="use-case-grid">
|
|
675
713
|
<div class="use-case">
|
|
676
|
-
<h3
|
|
714
|
+
<h3>Claude Code CLI</h3>
|
|
677
715
|
<p>Use Claude Code CLI from your phone. Run AI-powered coding commands using your own Claude API account.</p>
|
|
678
716
|
</div>
|
|
679
|
-
|
|
717
|
+
|
|
680
718
|
<div class="use-case">
|
|
681
|
-
<h3
|
|
719
|
+
<h3>Gemini CLI</h3>
|
|
682
720
|
<p>Use Gemini CLI from your phone. Access Google's AI tools with your own Google account and API access.</p>
|
|
683
721
|
</div>
|
|
684
|
-
|
|
722
|
+
|
|
685
723
|
<div class="use-case">
|
|
686
|
-
<h3
|
|
724
|
+
<h3>Standard Tools</h3>
|
|
687
725
|
<p>Git, npm, pip, Docker, SSH - all your usual command-line tools work normally from your phone.</p>
|
|
688
726
|
</div>
|
|
689
|
-
|
|
727
|
+
|
|
690
728
|
<div class="use-case">
|
|
691
|
-
<h3
|
|
729
|
+
<h3>Quick Fixes</h3>
|
|
692
730
|
<p>Fix bugs, check logs, or deploy code from your phone. Full access to your development environment.</p>
|
|
693
731
|
</div>
|
|
694
|
-
|
|
732
|
+
|
|
695
733
|
<div class="use-case">
|
|
696
|
-
<h3
|
|
734
|
+
<h3>Mobile Development</h3>
|
|
697
735
|
<p>Code during commutes or away from your desk. Follow tutorials and practice programming from your phone.</p>
|
|
698
736
|
</div>
|
|
699
|
-
|
|
737
|
+
|
|
700
738
|
<div class="use-case">
|
|
701
|
-
<h3
|
|
739
|
+
<h3>Personal Projects</h3>
|
|
702
740
|
<p>Work on personal projects from anywhere. Your own computer, your own accounts, your own code.</p>
|
|
703
741
|
</div>
|
|
704
742
|
</div>
|
|
@@ -708,24 +746,20 @@
|
|
|
708
746
|
<!-- Footer CTA -->
|
|
709
747
|
<section class="footer-cta" id="get-started">
|
|
710
748
|
<div class="container">
|
|
711
|
-
<h2>
|
|
712
|
-
<p>Access your terminal from anywhere
|
|
713
|
-
|
|
714
|
-
<div style="margin-top:
|
|
715
|
-
<button class="btn-primary" onclick="handleGoogleLogin()" style="
|
|
749
|
+
<h2>Get Started</h2>
|
|
750
|
+
<p>Access your terminal from anywhere</p>
|
|
751
|
+
|
|
752
|
+
<div style="margin-top: 32px; display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;">
|
|
753
|
+
<button class="btn-primary" onclick="handleGoogleLogin()" style="padding: 16px 32px;">Start Now</button>
|
|
716
754
|
<a href="https://github.com/karmalsky/shell-mirror" class="btn-secondary">View on GitHub</a>
|
|
717
755
|
</div>
|
|
718
|
-
|
|
719
|
-
<p style="margin-top: 30px; opacity: 0.8; font-size: 0.9rem;">
|
|
720
|
-
Free to use • Secure • No installation required
|
|
721
|
-
</p>
|
|
722
756
|
</div>
|
|
723
757
|
</section>
|
|
724
|
-
|
|
758
|
+
|
|
725
759
|
<!-- Version Footer -->
|
|
726
|
-
<footer style="background:
|
|
760
|
+
<footer style="background: var(--bg-secondary); color: var(--text-muted); text-align: center; padding: 16px 0; font-size: 0.75rem; border-top: 1px solid var(--border);">
|
|
727
761
|
<div class="container">
|
|
728
|
-
<p id="version-info">Shell Mirror
|
|
762
|
+
<p id="version-info">Shell Mirror</p>
|
|
729
763
|
</div>
|
|
730
764
|
</footer>
|
|
731
765
|
</main>
|
|
@@ -797,17 +831,10 @@
|
|
|
797
831
|
const response = await fetch('/build-info.json');
|
|
798
832
|
const buildInfo = await response.json();
|
|
799
833
|
const versionElement = document.getElementById('version-info');
|
|
800
|
-
|
|
801
|
-
|
|
834
|
+
|
|
802
835
|
if (versionElement && buildInfo) {
|
|
803
836
|
const buildDate = new Date(buildInfo.buildTime).toLocaleDateString();
|
|
804
|
-
versionElement.textContent = `Shell Mirror v${buildInfo.version}
|
|
805
|
-
|
|
806
|
-
// Apply random footer color from build info
|
|
807
|
-
if (footerElement && buildInfo.footerColor) {
|
|
808
|
-
footerElement.style.background = buildInfo.footerColor;
|
|
809
|
-
console.log(`🎨 Applied footer color: ${buildInfo.footerColor}`);
|
|
810
|
-
}
|
|
837
|
+
versionElement.textContent = `Shell Mirror v${buildInfo.version}`;
|
|
811
838
|
}
|
|
812
839
|
} catch (error) {
|
|
813
840
|
console.log('Could not load build info:', error);
|
|
@@ -881,12 +908,12 @@
|
|
|
881
908
|
// Update the Google login button in step 3 for authenticated users
|
|
882
909
|
const googleButton = document.querySelector('.btn-google');
|
|
883
910
|
if (googleButton && authStatus.isAuthenticated) {
|
|
884
|
-
googleButton.innerHTML = '
|
|
911
|
+
googleButton.innerHTML = 'Enter Dashboard';
|
|
885
912
|
googleButton.onclick = (e) => {
|
|
886
913
|
e.preventDefault();
|
|
887
914
|
openDashboard();
|
|
888
915
|
};
|
|
889
|
-
googleButton.style.background = '
|
|
916
|
+
googleButton.style.background = 'var(--accent)';
|
|
890
917
|
googleButton.style.color = 'white';
|
|
891
918
|
googleButton.style.border = 'none';
|
|
892
919
|
}
|
|
@@ -902,26 +929,23 @@
|
|
|
902
929
|
});
|
|
903
930
|
});
|
|
904
931
|
|
|
905
|
-
//
|
|
932
|
+
// Subtle fade-in for sections
|
|
906
933
|
const observerOptions = {
|
|
907
934
|
threshold: 0.1,
|
|
908
|
-
rootMargin: '0px 0px -
|
|
935
|
+
rootMargin: '0px 0px -20px 0px'
|
|
909
936
|
};
|
|
910
937
|
|
|
911
938
|
const observer = new IntersectionObserver((entries) => {
|
|
912
939
|
entries.forEach(entry => {
|
|
913
940
|
if (entry.isIntersecting) {
|
|
914
941
|
entry.target.style.opacity = '1';
|
|
915
|
-
entry.target.style.transform = 'translateY(0)';
|
|
916
942
|
}
|
|
917
943
|
});
|
|
918
944
|
}, observerOptions);
|
|
919
945
|
|
|
920
|
-
// Observe elements for animation
|
|
921
946
|
document.querySelectorAll('.step, .use-case').forEach(el => {
|
|
922
947
|
el.style.opacity = '0';
|
|
923
|
-
el.style.
|
|
924
|
-
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
|
948
|
+
el.style.transition = 'opacity 0.3s ease';
|
|
925
949
|
observer.observe(el);
|
|
926
950
|
});
|
|
927
951
|
</script>
|