Spaces:
Running
Running
| <html lang="id"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Jupiter — Login</title> | |
| <style> | |
| :root { | |
| --bg: #0f1117; | |
| --card: #1a1d29; | |
| --accent: #6366f1; | |
| --accent-hover: #4f46e5; | |
| --text: #e5e7eb; | |
| --muted: #9ca3af; | |
| --error: #ef4444; | |
| } | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| background: var(--bg); | |
| color: var(--text); | |
| min-height: 100vh; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 1rem; | |
| } | |
| .card { | |
| background: var(--card); | |
| border-radius: 16px; | |
| padding: 2.5rem; | |
| width: 100%; | |
| max-width: 380px; | |
| box-shadow: 0 20px 60px rgba(0,0,0,0.4); | |
| } | |
| .logo { | |
| font-size: 2.5rem; | |
| text-align: center; | |
| margin-bottom: 0.25rem; | |
| } | |
| h1 { | |
| text-align: center; | |
| font-size: 1.5rem; | |
| font-weight: 600; | |
| margin-bottom: 0.25rem; | |
| } | |
| .subtitle { | |
| text-align: center; | |
| color: var(--muted); | |
| font-size: 0.875rem; | |
| margin-bottom: 1.75rem; | |
| } | |
| .target-info { | |
| text-align: center; | |
| color: var(--accent); | |
| font-size: 0.85rem; | |
| background: rgba(99, 102, 241, 0.1); | |
| border: 1px solid rgba(99, 102, 241, 0.3); | |
| border-radius: 8px; | |
| padding: 0.5rem 0.75rem; | |
| margin-bottom: 1.25rem; | |
| display: none; | |
| } | |
| .target-info.show { display: block; } | |
| label { | |
| display: block; | |
| font-size: 0.875rem; | |
| color: var(--muted); | |
| margin-bottom: 0.5rem; | |
| } | |
| input[type="password"] { | |
| width: 100%; | |
| padding: 0.875rem 1rem; | |
| border-radius: 10px; | |
| border: 1px solid #2d3142; | |
| background: #0f1117; | |
| color: var(--text); | |
| font-size: 1rem; | |
| outline: none; | |
| transition: border-color 0.2s; | |
| } | |
| input[type="password"]:focus { | |
| border-color: var(--accent); | |
| } | |
| button { | |
| width: 100%; | |
| margin-top: 1.25rem; | |
| padding: 0.875rem; | |
| border-radius: 10px; | |
| border: none; | |
| background: var(--accent); | |
| color: white; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| } | |
| button:hover { background: var(--accent-hover); } | |
| .error { | |
| background: rgba(239, 68, 68, 0.1); | |
| color: var(--error); | |
| border: 1px solid rgba(239, 68, 68, 0.3); | |
| border-radius: 10px; | |
| padding: 0.75rem; | |
| text-align: center; | |
| font-size: 0.875rem; | |
| margin-bottom: 1.25rem; | |
| display: none; | |
| } | |
| .error.show { display: block; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="card"> | |
| <div class="logo">🪐</div> | |
| <h1>Jupiter</h1> | |
| <p class="subtitle">Masukkan password untuk lanjut</p> | |
| <div id="targetInfo" class="target-info"> | |
| 🔗 Mengakses port: <strong id="targetPort"></strong> | |
| </div> | |
| <div id="error" class="error">Password salah, coba lagi.</div> | |
| <form method="POST" action="/login" id="loginForm"> | |
| <input type="hidden" name="next" id="nextField" value="/"> | |
| <label for="password">Password</label> | |
| <input type="password" id="password" name="password" autofocus required | |
| placeholder="••••••••••••"> | |
| <button type="submit">Masuk →</button> | |
| </form> | |
| </div> | |
| <script> | |
| // Parse ?next= and ?error= from URL | |
| var params = new URLSearchParams(window.location.search); | |
| var nextUrl = params.get("next") || "/"; | |
| // Set the hidden "next" field so the form submits to the right place | |
| document.getElementById("nextField").value = nextUrl; | |
| // Show which port the user is trying to access | |
| var portMatch = nextUrl.match(/^\/(\d+)\//); | |
| if (portMatch) { | |
| document.getElementById("targetPort").textContent = "localhost:" + portMatch[1]; | |
| document.getElementById("targetInfo").classList.add("show"); | |
| } | |
| // Show error banner | |
| if (params.get("error") === "1") { | |
| document.getElementById("error").classList.add("show"); | |
| } | |
| </script> | |
| </body> | |
| </html> | |