shell-mirror
Version:
Access your Mac shell from any device securely. Perfect for mobile coding with Claude Code CLI, Gemini CLI, and any shell tool.
747 lines (645 loc) • 23.7 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shell Mirror - Use Claude Code CLI and Gemini CLI from your phone</title>
<meta name="description" content="Access your Mac terminal from your phone to use Claude Code CLI, Gemini CLI, and other command-line tools. Your computer, your accounts, secure access.">
<meta name="keywords" content="mobile coding, remote shell, Claude Code mobile, Gemini CLI phone, Mac shell browser, secure shell sharing">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:title" content="Shell Mirror - Use Claude Code CLI and Gemini CLI from your phone">
<meta property="og:description" content="Access your Mac terminal from your phone to use Claude Code CLI, Gemini CLI, and other tools. Your computer, your accounts.">
<meta property="og:url" content="https://www.igori.eu">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:title" content="Shell Mirror - Use Claude Code CLI from your phone">
<meta property="twitter:description" content="Access your Mac terminal from your phone to use Claude Code CLI, Gemini CLI, and other command-line tools.">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Header */
header {
padding: 20px 0;
position: relative;
z-index: 100;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 24px;
font-weight: bold;
color: white;
}
.cta-button {
background: rgba(255, 255, 255, 0.2);
color: white;
padding: 12px 24px;
text-decoration: none;
border-radius: 25px;
font-weight: 500;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
}
.cta-button:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
/* Hero Section */
.hero {
text-align: center;
padding: 60px 0 80px;
color: white;
}
.hero h1 {
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 700;
margin-bottom: 20px;
line-height: 1.2;
}
.hero p {
font-size: clamp(1.1rem, 2vw, 1.3rem);
margin-bottom: 40px;
opacity: 0.9;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.hero-buttons {
display: flex;
gap: 20px;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 60px;
}
.btn-primary {
background: #4285F4;
color: white;
padding: 16px 32px;
text-decoration: none;
border-radius: 30px;
font-weight: 600;
font-size: 1.1rem;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(66, 133, 244, 0.3);
}
.btn-primary:hover {
background: #3367d6;
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(66, 133, 244, 0.4);
}
.btn-secondary {
background: transparent;
color: white;
padding: 16px 32px;
text-decoration: none;
border-radius: 30px;
font-weight: 600;
font-size: 1.1rem;
border: 2px solid white;
transition: all 0.3s ease;
}
.btn-secondary:hover {
background: white;
color: #667eea;
}
/* Setup Steps */
.setup-steps {
margin: 40px auto;
max-width: 600px;
display: flex;
flex-direction: column;
gap: 20px;
}
.setup-step {
display: flex;
align-items: center;
gap: 20px;
}
.step-number {
font-size: 2rem;
font-weight: bold;
color: white;
opacity: 0.8;
min-width: 40px;
text-align: center;
}
/* Installation Code */
.install-code {
background: rgba(0, 0, 0, 0.3);
padding: 20px;
border-radius: 15px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
flex: 1;
height: 60px;
display: flex;
align-items: center;
}
.install-code pre {
color: #00ff88;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 1.1rem;
margin: 0;
padding-right: 40px;
flex: 1;
}
.copy-btn {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 8px;
color: white;
cursor: pointer;
transition: all 0.2s ease;
}
.copy-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-50%) scale(1.05);
}
.copy-btn:active {
transform: translateY(-50%) scale(0.95);
}
.copy-btn svg {
display: block;
}
/* Google Login Button */
.btn-google {
background: white;
color: #3c4043;
padding: 20px 24px;
border: 1px solid #dadce0;
border-radius: 15px;
font-weight: 500;
font-size: 1rem;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
transition: all 0.2s ease;
cursor: pointer;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
flex: 1;
height: 60px;
}
.btn-google:hover {
background: #f8f9fa;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
/* transform: translateY(-1px); */
}
.btn-google:active {
transform: translateY(0);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* Installation Modal */
.install-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
align-items: center;
justify-content: center;
}
.install-modal.show {
display: flex;
}
.install-modal-content {
background: white;
padding: 30px;
border-radius: 15px;
max-width: 500px;
margin: 20px;
text-align: center;
position: relative;
}
.install-modal-content h3 {
color: #333;
margin-bottom: 20px;
}
.install-modal-content p {
color: #666;
margin-bottom: 20px;
}
.install-modal-content .install-code {
background: #f5f5f5;
color: #333;
margin: 20px 0;
}
.install-modal-content .install-code pre {
color: #333;
}
.close-modal {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
}
.close-modal:hover {
color: #000;
}
/* How It Works */
.how-it-works {
background: white;
padding: 80px 0;
}
.section-title {
text-align: center;
font-size: 2.5rem;
margin-bottom: 60px;
color: #333;
}
.steps {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 40px;
margin-bottom: 60px;
}
.step {
text-align: center;
padding: 30px 20px;
}
.step-icon {
width: 80px;
height: 80px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 20px;
font-size: 2rem;
color: white;
}
.step h3 {
font-size: 1.3rem;
margin-bottom: 15px;
color: #333;
}
.step p {
color: #666;
line-height: 1.6;
}
/* Security Section */
.security {
background: #f8f9fa;
padding: 80px 0;
}
.security-flow {
display: flex;
align-items: center;
justify-content: center;
gap: 30px;
flex-wrap: wrap;
margin: 40px 0;
}
.security-step {
background: white;
padding: 20px;
border-radius: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
text-align: center;
min-width: 200px;
}
.security-step h4 {
color: #4285F4;
margin-bottom: 10px;
}
.arrow {
font-size: 2rem;
color: #4285F4;
}
/* Use Cases */
.use-cases {
padding: 80px 0;
background: white;
}
.use-case-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
}
.use-case {
background: #f8f9fa;
padding: 30px;
border-radius: 15px;
border-left: 4px solid #4285F4;
}
.use-case h3 {
color: #333;
margin-bottom: 15px;
}
.use-case p {
color: #666;
}
/* Footer CTA */
.footer-cta {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 60px 0;
text-align: center;
color: white;
}
.footer-cta h2 {
font-size: 2.5rem;
margin-bottom: 20px;
}
.footer-cta p {
font-size: 1.2rem;
margin-bottom: 40px;
opacity: 0.9;
}
/* Responsive Design */
@media (max-width: 768px) {
.setup-steps {
max-width: 90%;
gap: 15px;
}
.setup-step {
gap: 15px;
}
.step-number {
font-size: 1.5rem;
min-width: 30px;
}
.install-code {
height: 50px;
padding: 15px;
}
.btn-google {
height: 50px;
padding: 15px 20px;
font-size: 0.9rem;
}
.hero-buttons {
flex-direction: column;
align-items: center;
}
.btn-primary {
width: 250px;
}
.security-flow {
flex-direction: column;
}
.arrow {
transform: rotate(90deg);
}
.steps {
grid-template-columns: 1fr;
}
}
/* Animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.hero, .step, .use-case {
animation: fadeInUp 0.6s ease-out;
}
</style>
</head>
<body>
<header>
<nav class="container">
<div class="logo">Shell Mirror</div>
<a href="/app" class="cta-button">Launch App</a>
</nav>
</header>
<main>
<!-- Hero Section -->
<section class="hero">
<div class="container">
<h1>Access your Mac terminal<br>from anywhere</h1>
<p>Cloud-based terminal access for your Mac. Use Claude Code CLI, Gemini CLI, and other command-line tools from your phone or any device.</p>
<div class="hero-buttons">
<button class="btn-primary" onclick="handleGoogleLogin()">
<svg width="20" height="20" viewBox="0 0 24 24" style="margin-right: 8px;">
<path fill="white" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
<path fill="white" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
<path fill="white" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
<path fill="white" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
</svg>
Start with Google
</button>
<a href="#how-it-works" class="btn-secondary">Learn More</a>
</div>
</div>
</section>
<!-- How It Works -->
<section class="how-it-works" id="how-it-works">
<div class="container">
<h2 class="section-title">How Shell Mirror Works</h2>
<div class="steps">
<div class="step">
<div class="step-icon">🔐</div>
<h3>Secure Login</h3>
<p>Sign in with your Google account. Your credentials are encrypted and secure.</p>
</div>
<div class="step">
<div class="step-icon">🌐</div>
<h3>Cloud Terminal</h3>
<p>Access a cloud-based terminal environment with all your favorite command-line tools pre-installed.</p>
</div>
<div class="step">
<div class="step-icon">📱</div>
<h3>Any Device</h3>
<p>Use from your phone, tablet, or any web browser. Your terminal is always accessible.</p>
</div>
</div>
</div>
</section>
<!-- Security -->
<section class="security" id="security">
<div class="container">
<h2 class="section-title">Secure & Reliable</h2>
<p style="text-align: center; margin-bottom: 40px; color: #666; font-size: 1.1rem;">
Enterprise-grade security with Google OAuth authentication.
</p>
<div class="security-flow">
<div class="security-step">
<h4>Your Device</h4>
<p>Any web browser</p>
</div>
<div class="arrow">→</div>
<div class="security-step">
<h4>Secure Login</h4>
<p>Google OAuth 2.0</p>
</div>
<div class="arrow">→</div>
<div class="security-step">
<h4>Cloud Terminal</h4>
<p>Instant access</p>
</div>
</div>
<div style="text-align: center; margin-top: 40px;">
<p style="color: #666;">✅ Encrypted connections (HTTPS/WSS)<br>
✅ Google-grade authentication<br>
✅ Session-based security<br>
✅ No local installation required</p>
</div>
</div>
</section>
<!-- Use Cases -->
<section class="use-cases" id="use-cases">
<div class="container">
<h2 class="section-title">Use Cases</h2>
<div class="use-case-grid">
<div class="use-case">
<h3>🤖 Claude Code CLI</h3>
<p>Use Claude Code CLI from your phone. Run AI-powered coding commands using your own Claude API account.</p>
</div>
<div class="use-case">
<h3>✨ Gemini CLI</h3>
<p>Use Gemini CLI from your phone. Access Google's AI tools with your own Google account and API access.</p>
</div>
<div class="use-case">
<h3>🔧 Standard Tools</h3>
<p>Git, npm, pip, Docker, SSH - all your usual command-line tools work normally from your phone.</p>
</div>
<div class="use-case">
<h3>🔧 Quick Fixes</h3>
<p>Fix bugs, check logs, or deploy code from your phone. Full access to your development environment.</p>
</div>
<div class="use-case">
<h3>📱 Mobile Development</h3>
<p>Code during commutes or away from your desk. Follow tutorials and practice programming from your phone.</p>
</div>
<div class="use-case">
<h3>🏠 Personal Projects</h3>
<p>Work on personal projects from anywhere. Your own computer, your own accounts, your own code.</p>
</div>
</div>
</div>
</section>
<!-- Footer CTA -->
<section class="footer-cta" id="get-started">
<div class="container">
<h2>Ready to Start?</h2>
<p>Access your terminal from anywhere in seconds</p>
<div style="margin-top: 40px;">
<button class="btn-primary" onclick="handleGoogleLogin()" style="margin-right: 20px; padding: 20px 40px; font-size: 1.2rem;">Start Now</button>
<a href="https://github.com/karmalsky/shell-mirror" class="btn-secondary">View on GitHub</a>
</div>
<p style="margin-top: 30px; opacity: 0.8; font-size: 0.9rem;">
Free to use • Secure • No installation required
</p>
</div>
</section>
<!-- Version Footer -->
<footer style="background: #1a1a1a; color: #666; text-align: center; padding: 20px 0; font-size: 0.8rem;">
<div class="container">
<p id="version-info">Shell Mirror v1.5.2 • Loading build info...</p>
</div>
</footer>
</main>
<script>
// Check if user is already authenticated and redirect to terminal
async function checkAuthAndRedirect() {
try {
const response = await fetch('/php-backend/api/auth-status.php');
const data = await response.json();
if (data.success && data.data && data.data.authenticated) {
// User is logged in, redirect to terminal
window.location.href = '/app/terminal.html';
return true;
}
} catch (error) {
console.log('Auth check failed:', error);
}
return false;
}
// Handle Google login - direct web OAuth
async function handleGoogleLogin() {
// Check if already logged in first
const isLoggedIn = await checkAuthAndRedirect();
if (isLoggedIn) return;
// Direct OAuth flow using the web backend
window.location.href = '/php-backend/api/auth-login.php';
}
// Load version info
async function loadVersionInfo() {
try {
const response = await fetch('/build-info.json');
const buildInfo = await response.json();
const versionElement = document.getElementById('version-info');
if (versionElement && buildInfo) {
const buildDate = new Date(buildInfo.buildTime).toLocaleDateString();
versionElement.textContent = `Shell Mirror v${buildInfo.version} • Built ${buildDate}`;
}
} catch (error) {
console.log('Could not load build info:', error);
}
}
// Check authentication status on page load
document.addEventListener('DOMContentLoaded', () => {
checkAuthAndRedirect();
loadVersionInfo();
});
// Smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
// Add intersection observer for animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
}, observerOptions);
// Observe elements for animation
document.querySelectorAll('.step, .use-case').forEach(el => {
el.style.opacity = '0';
el.style.transform = 'translateY(30px)';
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
observer.observe(el);
});
</script>
</body>
</html>