Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Login / Signup - CTRL + ALT + HEAL</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link | |
| href="https://fonts.googleapis.com/css2?family=Rubik:wght@400;700&display=swap" | |
| rel="stylesheet" | |
| /> | |
| <style> | |
| :root { | |
| --tropical-indigo: rgb(120, 187, 242); | |
| --wisteria: rgb(197, 217, 251); | |
| --latte-cream: #ffffff; | |
| } | |
| body { | |
| font-family: "Rubik", sans-serif; | |
| background-color: var(--latte-cream); | |
| color: #333; | |
| } | |
| .glass-card { | |
| background: rgba(162, 160, 160, 0.075); | |
| backdrop-filter: blur(12px); | |
| border-radius: 1rem; | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| padding: 2rem; | |
| transition: transform 0.3s ease, box-shadow 0.3s ease; | |
| } | |
| .glass-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 15px 25px rgba(0, 0, 0, 0.2); | |
| } | |
| .nav-link { | |
| position: relative; | |
| padding-bottom: 4px; | |
| transition: color 0.3s; | |
| } | |
| .nav-link::after { | |
| content: ""; | |
| position: absolute; | |
| width: 0%; | |
| height: 2px; | |
| bottom: 0; | |
| left: 0; | |
| background-color: var(--tropical-indigo); | |
| transition: width 0.3s ease; | |
| } | |
| .nav-link:hover::after { | |
| width: 100%; | |
| } | |
| .nav-link.active-page::after { | |
| width: 100%; | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen flex flex-col"> | |
| <!-- NAVBAR --> | |
| <nav | |
| class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md" | |
| > | |
| <div class="flex justify-between items-center w-full px-6 py-4"> | |
| <a | |
| href="index.html" | |
| class="text-2xl font-bold text-black hover:text-[var(--tropical-indigo)] transition" | |
| > | |
| CTRL + ALT + HEAL | |
| </a> | |
| <!-- Desktop Menu --> | |
| <ul class="hidden md:flex space-x-6 font-medium text-gray-800"> | |
| <li><a href="index.html" class="nav-link">Home</a></li> | |
| <li><a href="profile.html" class="nav-link">Profile</a></li> | |
| <li><a href="analyzer.html" class="nav-link">Analyzer</a></li> | |
| <li><a href="past_data.html" class="nav-link">Past Report</a></li> | |
| <button | |
| id="hamburger" | |
| class="md:hidden text-[var(--latte-cream)] text-2xl" | |
| > | |
| ☰ | |
| </button> | |
| </div> | |
| <ul | |
| id="mobile-menu" | |
| class="hidden flex-col space-y-4 bg-white/30 backdrop-blur-lg border border-white/20 rounded-xl shadow-lg mt-2 p-4 mx-6 md:hidden" | |
| > | |
| <li><a href="index.html" class="block text-gray-800">Home</a></li> | |
| <li> | |
| <a href="analyzer.html" class="block text-gray-800">Analyzer</a> | |
| </li> | |
| <li><a href="profile.html" class="block text-gray-800">Profile</a></li> | |
| <li> | |
| <a href="login.html" class="block text-gray-800 active-page">Login</a> | |
| </li> | |
| </ul> | |
| </nav> | |
| <!-- LOGIN FORM --> | |
| <main class="flex flex-1 items-center justify-center pt-28 px-6"> | |
| <div class="glass-card w-full max-w-md text-center"> | |
| <h2 class="text-3xl font-bold text-[var(--tropical-indigo)] mb-6"> | |
| Sign In / Sign Up | |
| </h2> | |
| <select | |
| id="modeSelector" | |
| onchange="toggleMode(this.value)" | |
| class="w-full mb-4 px-4 py-2 border rounded-lg" | |
| > | |
| <option value="login">Log In</option> | |
| <option value="signup">Sign Up</option> | |
| </select> | |
| <input | |
| type="email" | |
| id="email" | |
| placeholder="Email" | |
| class="w-full mb-4 px-4 py-2 border rounded-lg" | |
| /> | |
| <input | |
| type="password" | |
| id="password" | |
| placeholder="Password" | |
| class="w-full mb-4 px-4 py-2 border rounded-lg" | |
| /> | |
| <div id="nameGroup" style="display: none"> | |
| <input | |
| type="text" | |
| id="name" | |
| placeholder="Full Name" | |
| class="w-full mb-4 px-4 py-2 border rounded-lg" | |
| /> | |
| </div> | |
| <div id="dobGroup" style="display: none"> | |
| <input | |
| type="date" | |
| id="dob" | |
| class="w-full mb-4 px-4 py-2 border rounded-lg" | |
| /> | |
| </div> | |
| <p id="error-message" class="text-red-500 text-sm mb-4"></p> | |
| <button | |
| id="submitBtn" | |
| class="w-full bg-[var(--tropical-indigo)] text-white py-2 rounded-lg hover:bg-[var(--wisteria)] mb-2" | |
| > | |
| Log In | |
| </button> | |
| <button | |
| onclick="resetPassword()" | |
| class="w-full bg-gray-200 text-gray-800 py-2 rounded-lg hover:bg-gray-300" | |
| > | |
| Reset Password | |
| </button> | |
| </div> | |
| </main> | |
| <!-- FOOTER --> | |
| <footer class="py-6 bg-[var(--wisteria)] text-white text-center"> | |
| © 2025 CTRL + ALT + HEAL. All rights reserved. | |
| </footer> | |
| <script type="module"> | |
| import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js"; | |
| import { | |
| getAuth, | |
| createUserWithEmailAndPassword, | |
| signInWithEmailAndPassword, | |
| sendPasswordResetEmail, | |
| } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-auth.js"; | |
| import { | |
| getFirestore, | |
| doc, | |
| setDoc, | |
| } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js"; | |
| const firebaseConfig = { | |
| apiKey: "AIzaSyAPhM_Ee7cLzyKHs5zyFy8g5ZOk9-pubRI", | |
| authDomain: "login-tutorial-7a9e1.firebaseapp.com", | |
| projectId: "login-tutorial-7a9e1", | |
| storageBucket: "login-tutorial-7a9e1.firebasestorage.app", | |
| messagingSenderId: "491093197824", | |
| appId: "1:491093197824:web:9f86659034af7e6a8244e5", | |
| measurementId: "G-JM7T9N6ZLZ" | |
| }; | |
| const app = initializeApp(firebaseConfig); | |
| const auth = getAuth(app); | |
| const db = getFirestore(app); | |
| let mode = "login"; | |
| const nameGroup = document.getElementById("nameGroup"); | |
| const dobGroup = document.getElementById("dobGroup"); | |
| const actionBtn = document.getElementById("submitBtn"); | |
| const errorElement = document.getElementById("error-message"); | |
| window.toggleMode = (newMode) => { | |
| mode = newMode; | |
| if (mode === "signup") { | |
| nameGroup.style.display = "block"; | |
| dobGroup.style.display = "block"; | |
| actionBtn.textContent = "Sign Up"; | |
| } else { | |
| nameGroup.style.display = "none"; | |
| dobGroup.style.display = "none"; | |
| actionBtn.textContent = "Log In"; | |
| } | |
| }; | |
| const getFriendlyErrorMessage = (error) => { | |
| switch (error.code) { | |
| case 'auth/invalid-email': | |
| return 'Invalid email format. Please try again.'; | |
| case 'auth/user-not-found': | |
| return 'No user found with this email.'; | |
| case 'auth/wrong-password': | |
| return 'Incorrect password. Please try again.'; | |
| case 'auth/weak-password': | |
| return 'Password is too weak. Please use at least 6 characters.'; | |
| case 'auth/invalid-login-credentials': | |
| return 'Invalid email or password. Please try again.'; | |
| case 'auth/email-already-in-use': | |
| return 'This email is already registered. Please log in or use a different email.'; | |
| case 'auth/email-already-exists': | |
| return 'This email is already registered. Please log in or use a different email.'; | |
| default: | |
| return 'An unknown error occurred. Please try again.'; | |
| } | |
| }; | |
| actionBtn.addEventListener("click", async (e) => { | |
| e.preventDefault(); | |
| const email = document.getElementById("email").value; | |
| const password = document.getElementById("password").value; | |
| errorElement.textContent = ""; | |
| if (mode === "signup") { | |
| try { | |
| const name = document.getElementById("name").value; | |
| const dob = document.getElementById("dob").value; | |
| const userCredential = await createUserWithEmailAndPassword( | |
| auth, | |
| email, | |
| password | |
| ); | |
| const user = userCredential.user; | |
| await setDoc(doc(db, "users", user.uid), { name, email, dob }); | |
| window.location.href = "profile.html"; | |
| } catch (err) { | |
| errorElement.textContent = getFriendlyErrorMessage(err); | |
| } | |
| } else { | |
| try { | |
| await signInWithEmailAndPassword(auth, email, password); | |
| window.location.href = "profile.html"; | |
| } catch (err) { | |
| errorElement.textContent = getFriendlyErrorMessage(err); | |
| } | |
| } | |
| }); | |
| window.resetPassword = async () => { | |
| const email = document.getElementById("email").value; | |
| if (!email) { | |
| errorElement.textContent = "Enter your email first!"; | |
| return; | |
| } | |
| try { | |
| await sendPasswordResetEmail(auth, email); | |
| alert("Password reset email sent!"); | |
| } catch (err) { | |
| errorElement.textContent = err.message; | |
| } | |
| }; | |
| </script> | |
| </body> | |
| </html> |