Dashboard: Changed stylesheet and started prepping html for population.
This commit is contained in:
27
dashboard.html
Normal file
27
dashboard.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Dashboard - MultiChatOverlay</title>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Dashboard</h1>
|
||||||
|
<p>Welcome, <strong>{{ user.username }}</strong>! You are successfully logged in.</p>
|
||||||
|
|
||||||
|
<div class="overlay-url-container">
|
||||||
|
<p>Your unique overlay URL:</p>
|
||||||
|
<code>{{ overlay_url }}</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><a href="/logout">Logout</a></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
main.py
18
main.py
@@ -1,8 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request, Depends
|
||||||
from starlette.middleware.sessions import SessionMiddleware
|
from starlette.middleware.sessions import SessionMiddleware
|
||||||
from starlette.staticfiles import StaticFiles
|
from starlette.staticfiles import StaticFiles
|
||||||
from starlette.responses import FileResponse, RedirectResponse
|
from starlette.responses import FileResponse, RedirectResponse
|
||||||
|
from fastapi.templating import Jinja2Templates
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
import models
|
import models
|
||||||
@@ -14,6 +15,7 @@ from config import settings # Import settings to get the secret key
|
|||||||
# Get the absolute path of the directory where this file is located
|
# Get the absolute path of the directory where this file is located
|
||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
STATIC_DIR = os.path.join(BASE_DIR, "static")
|
STATIC_DIR = os.path.join(BASE_DIR, "static")
|
||||||
|
TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
@@ -26,6 +28,9 @@ async def lifespan(app: FastAPI):
|
|||||||
|
|
||||||
app = FastAPI(lifespan=lifespan)
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
|
||||||
|
# Configure Jinja2 templates
|
||||||
|
templates = Jinja2Templates(directory=TEMPLATES_DIR)
|
||||||
|
|
||||||
# Mount the 'static' directory using an absolute path for reliability
|
# Mount the 'static' directory using an absolute path for reliability
|
||||||
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
||||||
|
|
||||||
@@ -41,12 +46,17 @@ async def read_root():
|
|||||||
return FileResponse(os.path.join(STATIC_DIR, "login.html"))
|
return FileResponse(os.path.join(STATIC_DIR, "login.html"))
|
||||||
|
|
||||||
@app.get("/dashboard")
|
@app.get("/dashboard")
|
||||||
async def read_dashboard(request: Request):
|
async def read_dashboard(request: Request, db: Session = Depends(auth.get_db)):
|
||||||
# This is our protected route. It checks if a user_id exists in the session.
|
# This is our protected route. It checks if a user_id exists in the session.
|
||||||
if not request.session.get('user_id'):
|
user_id = request.session.get('user_id')
|
||||||
|
if not user_id:
|
||||||
# If not, redirect them to the login page.
|
# If not, redirect them to the login page.
|
||||||
return RedirectResponse(url="/")
|
return RedirectResponse(url="/")
|
||||||
return FileResponse(os.path.join(STATIC_DIR, "dashboard.html"))
|
|
||||||
|
user = db.query(models.User).filter(models.User.id == user_id).first()
|
||||||
|
overlay_url = f"{settings.APP_BASE_URL}/overlay/{user.id}"
|
||||||
|
|
||||||
|
return templates.TemplateResponse("dashboard.html", {"request": request, "user": user, "overlay_url": overlay_url})
|
||||||
|
|
||||||
@app.get("/logout")
|
@app.get("/logout")
|
||||||
async def logout(request: Request):
|
async def logout(request: Request):
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ sqlalchemy
|
|||||||
httpx
|
httpx
|
||||||
cryptography
|
cryptography
|
||||||
python-dotenv
|
python-dotenv
|
||||||
itsdangerous
|
itsdangerous
|
||||||
|
jinja2
|
||||||
@@ -4,6 +4,11 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Login - MultiChatOverlay</title>
|
<title>Login - MultiChatOverlay</title>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
<link rel="stylesheet" href="/static/style.css">
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,27 +1,77 @@
|
|||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
/* Use a very dark grey background for contrast, making the container pop */
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
/* Suggest a modern font (requires import) */
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f0f2f5;
|
/* Use min-height for responsiveness */
|
||||||
|
background-color: #0d1117;
|
||||||
|
/* Dark Mode base color */
|
||||||
|
background-image: linear-gradient(135deg, #0d1117 0%, #161b22 100%);
|
||||||
|
/* Subtle gradient */
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: #e6edf3;
|
||||||
|
/* Light text color for contrast */
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 40px;
|
padding: 50px;
|
||||||
background-color: white;
|
/* Slightly more padding */
|
||||||
border-radius: 8px;
|
background-color: #161b22;
|
||||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
/* Lighter dark-mode color for the box */
|
||||||
}
|
border-radius: 12px;
|
||||||
|
/* Smoother corners */
|
||||||
|
|
||||||
|
/* Modern, subtle layered shadows for depth */
|
||||||
|
box-shadow:
|
||||||
|
0 4px 15px rgba(0, 0, 0, 0.4),
|
||||||
|
/* Primary shadow */
|
||||||
|
0 10px 30px rgba(0, 0, 0, 0.7);
|
||||||
|
/* Deep, soft shadow */
|
||||||
|
|
||||||
|
/* Optional: Small border for definition */
|
||||||
|
border: 1px solid #30363d;
|
||||||
|
|
||||||
|
/* Slightly increase size */
|
||||||
|
max-width: 380px;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
.twitch-btn {
|
.twitch-btn {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
|
/* Use flex for easy icon alignment if you add one */
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
/* Use a slightly brighter, but still core Twitch purple */
|
||||||
background-color: #9146FF;
|
background-color: #9146FF;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px 20px;
|
padding: 12px 28px;
|
||||||
border-radius: 5px;
|
/* Slightly larger padding */
|
||||||
|
border-radius: 8px;
|
||||||
|
/* Smoother corners */
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
|
/* Medium bold */
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
/* Better readability */
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
/* Enable smooth transitions */
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
/* Subtle inner shadow for 'pressed' look */
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a sleek hover effect */
|
||||||
|
.twitch-btn:hover {
|
||||||
|
background-color: #772ce8;
|
||||||
|
/* Slightly darker purple on hover */
|
||||||
|
transform: translateY(-2px);
|
||||||
|
/* Lift the button slightly */
|
||||||
|
box-shadow: 0 6px 12px rgba(145, 70, 255, 0.3);
|
||||||
|
/* Glow effect on hover */
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user