Move notifications to base template with bubble popup

- Added global notification system to base.html with bubble popups
- Notifications auto-disappear after 6 seconds with slide-out animation
- Manual close button for immediate dismissal
- Updated login.html and register.html to extend base template
- Removed duplicate notification code from individual templates
- Notifications now appear on all pages including login/register
parent 778da463
...@@ -21,6 +21,47 @@ ...@@ -21,6 +21,47 @@
.user-dropdown a { display: block; padding: 0.75rem 1rem; text-decoration: none; color: #374151; border-bottom: 1px solid #f1f5f9; } .user-dropdown a { display: block; padding: 0.75rem 1rem; text-decoration: none; color: #374151; border-bottom: 1px solid #f1f5f9; }
.user-dropdown a:last-child { border-bottom: none; color: #dc2626; } .user-dropdown a:last-child { border-bottom: none; color: #dc2626; }
.user-dropdown a:hover { background: #f8fafc; } .user-dropdown a:hover { background: #f8fafc; }
/* Notification styles */
.notification-container {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
max-width: 400px;
}
.notification {
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 1rem;
margin-bottom: 0.5rem;
border-left: 4px solid;
animation: slideIn 0.3s ease-out;
opacity: 1;
transform: translateX(0);
transition: all 0.3s ease;
}
.notification.success { border-left-color: #10b981; }
.notification.error { border-left-color: #ef4444; }
.notification.info { border-left-color: #3b82f6; }
.notification.warning { border-left-color: #f59e0b; }
.notification.fade-out {
opacity: 0;
transform: translateX(100%);
}
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
.notification-close {
float: right;
cursor: pointer;
font-weight: bold;
color: #6b7280;
margin-left: 1rem;
}
.notification-close:hover { color: #374151; }
</style> </style>
{% block head %}{% endblock %} {% block head %}{% endblock %}
</head> </head>
...@@ -58,6 +99,20 @@ ...@@ -58,6 +99,20 @@
</div> </div>
</header> </header>
<!-- Notification container -->
<div class="notification-container" id="notificationContainer">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="notification {{ category or 'info' }}" data-id="{{ loop.index }}">
<span class="notification-close" onclick="closeNotification(this)">&times;</span>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
{% block content %}{% endblock %} {% block content %}{% endblock %}
<script> <script>
...@@ -74,6 +129,32 @@ ...@@ -74,6 +129,32 @@
dropdown.style.display = 'none'; dropdown.style.display = 'none';
} }
} }
// Notification functions
function closeNotification(element) {
const notification = element.parentElement;
notification.classList.add('fade-out');
setTimeout(() => {
notification.remove();
}, 300);
}
function autoHideNotifications() {
const notifications = document.querySelectorAll('.notification');
notifications.forEach((notification, index) => {
setTimeout(() => {
notification.classList.add('fade-out');
setTimeout(() => {
notification.remove();
}, 300);
}, 6000 + (index * 500)); // Stagger hiding by 500ms
});
}
// Auto-hide notifications after page load
document.addEventListener('DOMContentLoaded', function() {
autoHideNotifications();
});
</script> </script>
</body> </body>
</html> </html>
\ No newline at end of file
<!DOCTYPE html> {% extends "base.html" %}
<html>
<head>
<title>Login - VidAI</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.login-container { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); width: 100%; max-width: 400px; }
.logo { text-align: center; font-size: 2rem; font-weight: 700; color: #667eea; margin-bottom: 2rem; }
.form-group { margin-bottom: 1.5rem; }
.form-group label { display: block; margin-bottom: 0.5rem; color: #374151; font-weight: 500; }
.form-group input { width: 100%; padding: 0.75rem; border: 2px solid #e5e7eb; border-radius: 8px; font-size: 1rem; }
.form-group input:focus { outline: none; border-color: #667eea; }
.btn { width: 100%; padding: 0.75rem; background: #667eea; color: white; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; }
.btn:hover { background: #5a67d8; }
.links { text-align: center; margin-top: 1.5rem; }
.links a { color: #667eea; text-decoration: none; margin: 0 0.5rem; }
.alert { padding: 0.75rem; border-radius: 8px; margin-bottom: 1rem; }
.alert-error { background: #fee2e2; color: #dc2626; border: 1px solid #fecaca; }
.alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
</style>
</head>
<body>
<div class="login-container">
<div class="logo">VidAI</div>
<form method="post">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'error' if category == 'error' else 'success' }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<div class="form-group"> {% block title %}Login - VidAI{% endblock %}
<label for="username">Username</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group"> {% block head %}
<label for="password">Password</label> <style>
<input type="password" id="password" name="password" required> body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; }
</div> .login-container { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); width: 100%; max-width: 400px; }
.logo { text-align: center; font-size: 2rem; font-weight: 700; color: #667eea; margin-bottom: 2rem; }
.form-group { margin-bottom: 1.5rem; }
.form-group label { display: block; margin-bottom: 0.5rem; color: #374151; font-weight: 500; }
.form-group input { width: 100%; padding: 0.75rem; border: 2px solid #e5e7eb; border-radius: 8px; font-size: 1rem; }
.form-group input:focus { outline: none; border-color: #667eea; }
.btn { width: 100%; padding: 0.75rem; background: #667eea; color: white; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; }
.btn:hover { background: #5a67d8; }
.links { text-align: center; margin-top: 1.5rem; }
.links a { color: #667eea; text-decoration: none; margin: 0 0.5rem; }
</style>
{% endblock %}
<div class="form-group" style="display: flex; align-items: center; gap: 0.5rem;"> {% block content %}
<input type="checkbox" id="remember" name="remember"> <div class="login-container">
<label for="remember" style="margin: 0; font-weight: normal;">Remember me</label> <div class="logo">VidAI</div>
</div> <form method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" required>
</div>
<button type="submit" class="btn">Login</button> <div class="form-group">
</form> <label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<div class="links"> <div class="form-group" style="display: flex; align-items: center; gap: 0.5rem;">
<a href="/register">Create Account</a> | <input type="checkbox" id="remember" name="remember">
<a href="/">Home</a> <label for="remember" style="margin: 0; font-weight: normal;">Remember me</label>
</div> </div>
<button type="submit" class="btn">Login</button>
</form>
<div class="links">
<a href="/register">Create Account</a> |
<a href="/">Home</a>
</div> </div>
</body> </div>
</html> {% endblock %}
\ No newline at end of file \ No newline at end of file
<!DOCTYPE html> {% extends "base.html" %}
<html>
<head>
<title>Register - VidAI</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.register-container { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); width: 100%; max-width: 400px; }
.logo { text-align: center; font-size: 2rem; font-weight: 700; color: #667eea; margin-bottom: 2rem; }
.form-group { margin-bottom: 1.5rem; }
.form-group label { display: block; margin-bottom: 0.5rem; color: #374151; font-weight: 500; }
.form-group input { width: 100%; padding: 0.75rem; border: 2px solid #e5e7eb; border-radius: 8px; font-size: 1rem; }
.form-group input:focus { outline: none; border-color: #667eea; }
.btn { width: 100%; padding: 0.75rem; background: #667eea; color: white; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; }
.btn:hover { background: #5a67d8; }
.links { text-align: center; margin-top: 1.5rem; }
.links a { color: #667eea; text-decoration: none; margin: 0 0.5rem; }
.alert { padding: 0.75rem; border-radius: 8px; margin-bottom: 1rem; }
.alert-error { background: #fee2e2; color: #dc2626; border: 1px solid #fecaca; }
.alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
</style>
</head>
<body>
<div class="register-container">
<div class="logo">VidAI</div>
<form method="post">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'error' if category == 'error' else 'success' }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<div class="form-group"> {% block title %}Register - VidAI{% endblock %}
<label for="username">Username</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group"> {% block head %}
<label for="email">Email</label> <style>
<input type="email" id="email" name="email" required> body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; }
</div> .register-container { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); width: 100%; max-width: 400px; }
.logo { text-align: center; font-size: 2rem; font-weight: 700; color: #667eea; margin-bottom: 2rem; }
.form-group { margin-bottom: 1.5rem; }
.form-group label { display: block; margin-bottom: 0.5rem; color: #374151; font-weight: 500; }
.form-group input { width: 100%; padding: 0.75rem; border: 2px solid #e5e7eb; border-radius: 8px; font-size: 1rem; }
.form-group input:focus { outline: none; border-color: #667eea; }
.btn { width: 100%; padding: 0.75rem; background: #667eea; color: white; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; }
.btn:hover { background: #5a67d8; }
.links { text-align: center; margin-top: 1.5rem; }
.links a { color: #667eea; text-decoration: none; margin: 0 0.5rem; }
</style>
{% endblock %}
<div class="form-group"> {% block content %}
<label for="password">Password</label> <div class="register-container">
<input type="password" id="password" name="password" required> <div class="logo">VidAI</div>
</div> <form method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" required>
</div>
<button type="submit" class="btn">Create Account</button> <div class="form-group">
</form> <label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div class="links"> <div class="form-group">
<a href="/login">Already have an account?</a> | <label for="password">Password</label>
<a href="/">Home</a> <input type="password" id="password" name="password" required>
</div> </div>
<button type="submit" class="btn">Create Account</button>
</form>
<div class="links">
<a href="/login">Already have an account?</a> |
<a href="/">Home</a>
</div> </div>
</body> </div>
</html> {% endblock %}
\ No newline at end of file \ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment