Unify login via popup on home. No need for separate login html page.

Delete old login html page. Login via popup on home is the single,
unified login experience.

Have docs mention khoj home url, no need to mention /login as login
popup shows on home page too
This commit is contained in:
Debanjum
2025-12-28 17:11:52 -08:00
parent f65f6ae848
commit 5e65754a8b
7 changed files with 11 additions and 328 deletions

View File

@@ -1,310 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>Khoj - Login</title>
<link rel="icon" type="image/png" sizes="128x128" href="https://assets.khoj.dev/khoj_lantern_128x128.png">
<link rel="manifest" href="/static/khoj.webmanifest">
<link rel="stylesheet" href="/static/assets/khoj.css">
<meta property="og:image" content="https://assets.khoj.dev/khoj_hero.png">
</head>
<body>
<div class="split-container">
<!-- Left side with login -->
<div class="split left">
<div id="login-modal">
<img class="khoj-logo" src="https://assets.khoj.dev/khoj_lantern_128x128.png" alt="Khoj">
<div class="login-modal-title">Login to Khoj</div>
<!-- Sign Up/Login with Google OAuth -->
<div class="g_id_signin" data-shape="circle" data-text="continue_with" data-logo_alignment="center"
data-size="large" data-type="standard"></div>
<div id="g_id_onload" data-client_id="{{ google_client_id }}" data-ux_mode="popup"
data-use_fedcm_for_prompt="true" data-login_uri="{{ redirect_uri }}" data-auto-select="true"></div>
<!-- Divider -->
<div class="divider">OR</div>
<!-- Sign in with Magic Link -->
<div class="khoj-magic-link">
<input type="email" id="email" placeholder="Email" autofocus required>
<button id="magic-link-button">Get Login Link</button>
</div>
</div>
<!-- Footer links -->
<div class="footer-links">
<a href="https://khoj.dev/terms-of-service" target="_blank">Terms of Service</a>
<span class="divider-vertical"></span>
<a href="https://khoj.dev/privacy-policy" target="_blank">Privacy Policy</a>
</div>
</div>
<!-- Right side with content -->
<div class="split right">
<div class="right-content">
<h1>Unlock Your Second Brain</h1>
<p>Transform the way you think, create, and remember</p>
<div class="features">
<div class="feature">
<img src="/static/assets/icons/chat.svg" alt="Chat" width="24" height="24">
<span>Get answers across your documents and the internet</span>
</div>
<div class="feature">
<img src="/static/assets/icons/agents.svg" alt="Agents" width="24" height="24">
<span>Create agents with the knowledge and tools to take on any role</span>
</div>
<div class="feature">
<img src="/static/assets/icons/automation.svg" alt="Automations" width="24" height="24">
<span>Automate away repetitive research</span>
</div>
</div>
</div>
</div>
</div>
<style>
body {
margin: 0;
height: 100vh;
font-family: 'Arial', sans-serif;
color: #333;
overflow: hidden;
}
.split-container {
display: flex;
height: 100vh;
}
.split {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.left {
background-color: #fff;
}
.right {
background: linear-gradient(135deg, #FFA07A 0%, #c4e4c6 100%);
color: white;
position: relative;
overflow: hidden;
}
.right::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0.1;
}
.right-content {
text-align: center;
padding: 2rem;
position: relative;
z-index: 1;
}
.right-content h1 {
font-size: 3rem;
margin-bottom: 1rem;
font-weight: 700;
}
.right-content p {
font-size: 1.2rem;
margin-bottom: 3rem;
opacity: 0.9;
}
.features {
display: flex;
flex-direction: column;
gap: 1.5rem;
align-items: center;
}
.feature {
display: flex;
align-items: center;
gap: 1rem;
font-size: 1.1rem;
}
.feature svg {
width: 24px;
height: 24px;
stroke: white;
}
.feature img {
width: 24px;
height: 24px;
filter: invert(100%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(100%) contrast(100%);
stroke: white;
}
#login-modal {
display: grid;
background: white;
border-radius: 10px;
padding: 40px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
text-align: center;
width: max-content;
}
.khoj-logo {
width: 80px;
margin-bottom: 20px;
}
.login-modal-title {
font-size: 24px;
font-weight: 600;
margin-bottom: 20px;
}
.khoj-magic-link {
display: flex;
flex-direction: column;
gap: 10px;
}
#email {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
width: 100%;
font-size: 16px;
}
#magic-link-button {
padding: 10px;
border: none;
border-radius: 5px;
background-color: #FFA07A;
color: white;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
#magic-link-button:hover {
background-color: #FFA07A
}
#magic-link-button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.divider {
display: flex;
align-items: center;
text-align: center;
color: #000;
/* Adjust the text color as needed */
margin: 20px 0;
/* Adjust the margin as needed */
}
.divider::before,
.divider::after {
content: '';
flex: 1;
border-bottom: 1px solid #000;
/* Adjust the line color as needed */
margin: 0 10px;
/* Adjust the spacing as needed */
}
.g_id_signin {
margin: 0 auto;
display: block;
}
.footer-links {
width: 100%;
text-align: center;
font-size: 0.9em;
color: #666;
margin-top: 20px;
}
.footer-links a {
color: #666;
text-decoration: none;
margin: 0 10px;
}
.footer-links a:hover {
text-decoration: underline;
}
.divider-vertical {
display: inline-block;
width: 1px;
height: 12px;
background-color: #666;
margin: 0 10px;
vertical-align: middle;
}
@media (max-width: 768px) {
.split-container {
flex-direction: column;
}
.right {
display: none;
}
.left {
padding: 2rem;
}
}
</style>
<script>
const magicLinkButton = document.getElementById('magic-link-button');
const emailInput = document.getElementById('email');
magicLinkButton.addEventListener('click', async () => {
const email = emailInput.value;
if (!email) {
alert('Please enter a valid email address');
return;
}
if (!email.includes('@')) {
alert('Please enter a valid email address');
return;
}
magicLinkButton.disabled = true;
magicLinkButton.innerText = 'Check your email for a sign-in link!';
const response = await fetch('/auth/magic', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ "email": email }),
});
if (response.status === 200) {
console.log('Magic link sent to your email');
} else {
alert('Failed to send magic link');
magicLinkButton.disabled = false;
magicLinkButton.innerText = 'Get Login Link';
}
});
</script>
<script src="https://accounts.google.com/gsi/client" async defer></script>
</body>
</html>

View File

@@ -1,6 +1,5 @@
# System Packages
import json
import os
from fastapi import APIRouter, Request
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
@@ -56,16 +55,10 @@ def login_page(request: Request):
next_url = get_next_url(request)
if request.user.is_authenticated:
return RedirectResponse(url=next_url)
google_client_id = os.environ.get("GOOGLE_CLIENT_ID")
redirect_uri = str(request.app.url_path_for("auth_post"))
return templates.TemplateResponse(
"login.html",
context={
"request": request,
"google_client_id": google_client_id,
"redirect_uri": f"{redirect_uri}?next={next_url}",
},
)
# Redirect to main app which shows the login popup for unauthenticated users
# Append v=app to prevent redirect loop back to /home
redirect_url = f"/?v=app&next={next_url}" if next_url != "/" else "/?v=app"
return RedirectResponse(url=redirect_url)
@web_client.get("/agents", response_class=HTMLResponse)