| <!DOCTYPE html>
|
| <html lang="de">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>NoahsKI - Login</title>
|
|
|
| <style>
|
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
|
|
| * {
|
| margin: 0;
|
| padding: 0;
|
| box-sizing: border-box;
|
| }
|
|
|
| body {
|
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
| background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
|
| min-height: 100vh;
|
| display: flex;
|
| align-items: center;
|
| justify-content: center;
|
| position: relative;
|
| overflow: hidden;
|
| }
|
|
|
|
|
| body::before {
|
| content: '';
|
| position: fixed;
|
| top: 0;
|
| left: 0;
|
| width: 100%;
|
| height: 100%;
|
| background:
|
| radial-gradient(circle at 20% 50%, rgba(139, 92, 246, 0.3) 0%, transparent 50%),
|
| radial-gradient(circle at 80% 80%, rgba(236, 72, 153, 0.3) 0%, transparent 50%),
|
| radial-gradient(circle at 40% 20%, rgba(59, 130, 246, 0.2) 0%, transparent 50%);
|
| animation: gradientShift 15s ease infinite;
|
| pointer-events: none;
|
| }
|
|
|
| @keyframes gradientShift {
|
| 0%, 100% { opacity: 1; }
|
| 50% { opacity: 0.8; }
|
| }
|
|
|
| .login-container {
|
| background: rgba(255, 255, 255, 0.1);
|
| backdrop-filter: blur(20px);
|
| -webkit-backdrop-filter: blur(20px);
|
| border-radius: 20px;
|
| border: 1px solid rgba(255, 255, 255, 0.2);
|
| box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
|
| padding: 50px 40px;
|
| width: 100%;
|
| max-width: 450px;
|
| position: relative;
|
| z-index: 1;
|
| animation: slideUp 0.6s ease;
|
| }
|
|
|
| @keyframes slideUp {
|
| from { transform: translateY(50px); opacity: 0; }
|
| to { transform: translateY(0); opacity: 1; }
|
| }
|
|
|
| .logo {
|
| text-align: center;
|
| margin-bottom: 40px;
|
| }
|
|
|
| .logo-icon {
|
| width: 80px;
|
| height: 80px;
|
| background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
| border-radius: 20px;
|
| display: inline-flex;
|
| align-items: center;
|
| justify-content: center;
|
| font-size: 40px;
|
| margin-bottom: 20px;
|
| animation: float 3s ease-in-out infinite;
|
| }
|
|
|
| @keyframes float {
|
| 0%, 100% { transform: translateY(0px); }
|
| 50% { transform: translateY(-10px); }
|
| }
|
|
|
| .logo h1 {
|
| font-size: 32px;
|
| font-weight: 800;
|
| background: linear-gradient(135deg, #fff, #e0e7ff);
|
| -webkit-background-clip: text;
|
| -webkit-text-fill-color: transparent;
|
| background-clip: text;
|
| margin-bottom: 10px;
|
| }
|
|
|
| .logo p {
|
| font-size: 14px;
|
| color: rgba(255, 255, 255, 0.8);
|
| font-weight: 500;
|
| }
|
|
|
| .form-group {
|
| margin-bottom: 25px;
|
| }
|
|
|
| .form-group label {
|
| display: block;
|
| color: white;
|
| font-weight: 600;
|
| margin-bottom: 10px;
|
| font-size: 14px;
|
| }
|
|
|
| .form-group input {
|
| width: 100%;
|
| padding: 15px 20px;
|
| border: 2px solid rgba(255, 255, 255, 0.2);
|
| border-radius: 12px;
|
| font-size: 15px;
|
| font-family: 'Inter', sans-serif;
|
| background: rgba(255, 255, 255, 0.9);
|
| color: #1f2937;
|
| outline: none;
|
| transition: all 0.3s ease;
|
| }
|
|
|
| .form-group input:focus {
|
| border-color: #8b5cf6;
|
| background: white;
|
| box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.1);
|
| }
|
|
|
| .login-btn {
|
| width: 100%;
|
| padding: 16px;
|
| background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
| color: white;
|
| border: none;
|
| border-radius: 12px;
|
| font-size: 16px;
|
| font-weight: 700;
|
| cursor: pointer;
|
| transition: all 0.3s ease;
|
| box-shadow: 0 4px 15px rgba(139, 92, 246, 0.4);
|
| }
|
|
|
| .login-btn:hover:not(:disabled) {
|
| transform: translateY(-2px);
|
| box-shadow: 0 6px 20px rgba(139, 92, 246, 0.5);
|
| }
|
|
|
| .login-btn:disabled {
|
| opacity: 0.6;
|
| cursor: not-allowed;
|
| }
|
|
|
| .error-message {
|
| background: rgba(239, 68, 68, 0.2);
|
| border: 1px solid rgba(239, 68, 68, 0.5);
|
| color: white;
|
| padding: 12px 16px;
|
| border-radius: 10px;
|
| margin-bottom: 20px;
|
| font-size: 14px;
|
| text-align: center;
|
| display: none;
|
| }
|
|
|
| .error-message.show {
|
| display: block;
|
| animation: shake 0.5s ease;
|
| }
|
|
|
| @keyframes shake {
|
| 0%, 100% { transform: translateX(0); }
|
| 25% { transform: translateX(-10px); }
|
| 75% { transform: translateX(10px); }
|
| }
|
|
|
| .success-message {
|
| background: rgba(16, 185, 129, 0.2);
|
| border: 1px solid rgba(16, 185, 129, 0.5);
|
| color: white;
|
| padding: 12px 16px;
|
| border-radius: 10px;
|
| margin-bottom: 20px;
|
| font-size: 14px;
|
| text-align: center;
|
| display: none;
|
| }
|
|
|
| .success-message.show {
|
| display: block;
|
| }
|
|
|
| .register-link {
|
| text-align: center;
|
| margin-top: 25px;
|
| color: rgba(255, 255, 255, 0.8);
|
| font-size: 14px;
|
| }
|
|
|
| .register-link a {
|
| color: white;
|
| font-weight: 600;
|
| text-decoration: none;
|
| border-bottom: 2px solid rgba(255, 255, 255, 0.5);
|
| transition: all 0.3s ease;
|
| }
|
|
|
| .register-link a:hover {
|
| border-bottom-color: white;
|
| }
|
|
|
| .loading {
|
| display: inline-block;
|
| width: 16px;
|
| height: 16px;
|
| border: 2px solid rgba(255, 255, 255, 0.3);
|
| border-radius: 50%;
|
| border-top-color: white;
|
| animation: spin 0.6s linear infinite;
|
| }
|
|
|
| @keyframes spin {
|
| to { transform: rotate(360deg); }
|
| }
|
|
|
|
|
| @media (max-width: 768px) {
|
| .login-container {
|
| padding: 40px 25px;
|
| max-width: 100%;
|
| margin: 0 20px;
|
| border-radius: 15px;
|
| }
|
|
|
| .logo-icon {
|
| width: 60px;
|
| height: 60px;
|
| font-size: 30px;
|
| margin-bottom: 15px;
|
| }
|
|
|
| .logo h1 {
|
| font-size: 28px;
|
| margin-bottom: 8px;
|
| }
|
|
|
| .logo p {
|
| font-size: 13px;
|
| }
|
|
|
| .form-group {
|
| margin-bottom: 20px;
|
| }
|
|
|
| .form-group label {
|
| font-size: 13px;
|
| margin-bottom: 8px;
|
| }
|
|
|
| .form-group input {
|
| padding: 12px 15px;
|
| font-size: 14px;
|
| border-radius: 10px;
|
| }
|
|
|
| .login-btn {
|
| padding: 14px;
|
| font-size: 15px;
|
| border-radius: 10px;
|
| }
|
|
|
| .error-message,
|
| .success-message {
|
| font-size: 13px;
|
| padding: 10px 14px;
|
| }
|
|
|
| .register-link {
|
| margin-top: 20px;
|
| font-size: 13px;
|
| }
|
| }
|
|
|
|
|
| @media (max-width: 480px) {
|
| body {
|
| padding: 10px;
|
| }
|
|
|
| .login-container {
|
| padding: 30px 18px;
|
| max-width: 100%;
|
| margin: 0 auto;
|
| border-radius: 12px;
|
| }
|
|
|
| .logo {
|
| margin-bottom: 30px;
|
| }
|
|
|
| .logo-icon {
|
| width: 50px;
|
| height: 50px;
|
| font-size: 24px;
|
| margin-bottom: 12px;
|
| }
|
|
|
| .logo h1 {
|
| font-size: 24px;
|
| margin-bottom: 6px;
|
| }
|
|
|
| .logo p {
|
| font-size: 12px;
|
| }
|
|
|
| .form-group {
|
| margin-bottom: 16px;
|
| }
|
|
|
| .form-group label {
|
| font-size: 12px;
|
| margin-bottom: 6px;
|
| font-weight: 600;
|
| }
|
|
|
| .form-group input {
|
| padding: 11px 12px;
|
| font-size: 13px;
|
| border-radius: 8px;
|
| }
|
|
|
| .login-btn {
|
| padding: 12px;
|
| font-size: 14px;
|
| border-radius: 8px;
|
| width: 100%;
|
| }
|
|
|
| .error-message,
|
| .success-message {
|
| font-size: 12px;
|
| padding: 9px 12px;
|
| margin-bottom: 16px;
|
| }
|
|
|
| .register-link {
|
| margin-top: 16px;
|
| font-size: 12px;
|
| }
|
|
|
| .register-link a {
|
| border-bottom-width: 1px;
|
| }
|
| }
|
| </style>
|
| </head>
|
| <body>
|
| <div class="login-container">
|
| <div class="logo">
|
| <div class="logo-icon">🧠</div>
|
| <h1>NoahsKI Ultimate</h1>
|
| <p>🔐 Secure Authentication</p>
|
| </div>
|
|
|
| <div id="error-message" class="error-message"></div>
|
| <div id="success-message" class="success-message"></div>
|
|
|
| <form id="login-form">
|
| <div class="form-group">
|
| <label for="email">📧 Email</label>
|
| <input
|
| type="email"
|
| id="email"
|
| name="email"
|
| placeholder="your@email.com"
|
| required
|
| autocomplete="email"
|
| >
|
| </div>
|
|
|
| <div class="form-group">
|
| <label for="password">🔒 Password</label>
|
| <input
|
| type="password"
|
| id="password"
|
| name="password"
|
| placeholder="Your password"
|
| required
|
| autocomplete="current-password"
|
| >
|
| </div>
|
|
|
| <button type="submit" class="login-btn" id="login-btn">
|
| ✨ Login
|
| </button>
|
| </form>
|
|
|
| <div class="register-link">
|
| Don't have an account? <a href="/register">Register here</a>
|
| </div>
|
| </div>
|
|
|
| <script>
|
| const loginForm = document.getElementById('login-form');
|
| const loginBtn = document.getElementById('login-btn');
|
| const errorMessage = document.getElementById('error-message');
|
| const successMessage = document.getElementById('success-message');
|
|
|
| function showError(message) {
|
| errorMessage.textContent = '❌ ' + message;
|
| errorMessage.classList.add('show');
|
| successMessage.classList.remove('show');
|
| setTimeout(() => {
|
| errorMessage.classList.remove('show');
|
| }, 5000);
|
| }
|
|
|
| function showSuccess(message) {
|
| successMessage.textContent = '✅ ' + message;
|
| successMessage.classList.add('show');
|
| errorMessage.classList.remove('show');
|
| }
|
|
|
|
|
| window.addEventListener('DOMContentLoaded', async function() {
|
| const token = getCookie('auth_token');
|
| if (token) {
|
| console.log('Token gefunden, validiere...');
|
| try {
|
| const response = await fetch('/api/auth/validate', {
|
| method: 'POST',
|
| headers: {
|
| 'Content-Type': 'application/json',
|
| 'Authorization': 'Bearer ' + token
|
| }
|
| });
|
|
|
| const data = await response.json();
|
| if (data.valid) {
|
| console.log('Token gültig, redirect zu /main');
|
| showSuccess('Already logged in! Redirecting...');
|
| setTimeout(() => {
|
| window.location.href = '/main';
|
| }, 500);
|
| }
|
| } catch (e) {
|
| console.log('Token-Validierung fehlgeschlagen:', e);
|
| }
|
| }
|
| });
|
|
|
| loginForm.addEventListener('submit', async function(e) {
|
| e.preventDefault();
|
|
|
| const email = document.getElementById('email').value.trim();
|
| const password = document.getElementById('password').value;
|
|
|
| if (!email || !password) {
|
| showError('Please fill in all fields');
|
| return;
|
| }
|
|
|
|
|
| loginBtn.disabled = true;
|
| loginBtn.innerHTML = '<span class="loading"></span> Logging in...';
|
|
|
| try {
|
| const response = await fetch('/api/auth/login', {
|
| method: 'POST',
|
| headers: {
|
| 'Content-Type': 'application/json'
|
| },
|
| body: JSON.stringify({ email, password })
|
| });
|
|
|
| const data = await response.json();
|
|
|
| if (response.ok && data.success) {
|
|
|
| if (data.token) {
|
| localStorage.setItem('auth_token', data.token);
|
| console.log('Token in localStorage gespeichert');
|
| }
|
|
|
| showSuccess('Login successful! Redirecting...');
|
| console.log('Login erfolgreich, redirect zu /main');
|
|
|
|
|
| setTimeout(() => {
|
| window.location.href = '/main';
|
| }, 1000);
|
| } else {
|
| showError(data.message || 'Login failed');
|
| loginBtn.disabled = false;
|
| loginBtn.innerHTML = '✨ Login';
|
| }
|
| } catch (error) {
|
| console.error('Login error:', error);
|
| showError('Connection error. Please try again.');
|
| loginBtn.disabled = false;
|
| loginBtn.innerHTML = '✨ Login';
|
| }
|
| });
|
|
|
| function getCookie(name) {
|
| const value = `; ${document.cookie}`;
|
| const parts = value.split(`; ${name}=`);
|
| if (parts.length === 2) return parts.pop().split(';').shift();
|
| return null;
|
| }
|
| </script>
|
| </body>
|
| </html> |