mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-02 21:19:12 +00:00
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:
@@ -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>
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user