feat(ui): add error handling, flash messages and SEO optimization
- Add custom error pages (404, 403, 500) with user-friendly messages
- Add flash message system with signed cookies for security
- Add toast notifications with auto-dismiss and manual close
- Add comprehensive SEO meta tags (description, keywords, OG, Twitter)
- Add canonical URLs for SEO
- Update routes to use slug-based URLs (/posts/{slug} instead of /posts/{id})
- Add Open Graph and Twitter Card meta tags for social sharing
- Add favicon SVG
- Update all templates with proper meta tags and URLs
- Add error handlers registration in main.py
- Add flash middleware for request handling
- Install itsdangerous dependency
This commit is contained in:
69
static/js/flash.js
Normal file
69
static/js/flash.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Flash messages functionality for blog application.
|
||||
*
|
||||
* Handles auto-dismissal and manual closing of flash messages.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const AUTO_DISMISS_DELAY = 5000; // 5 seconds
|
||||
|
||||
function initFlashMessages() {
|
||||
const flashMessages = document.querySelectorAll('[data-testid^="flash-message-"]');
|
||||
|
||||
flashMessages.forEach(function(message) {
|
||||
const closeBtn = message.querySelector('[data-testid="flash-close"]');
|
||||
|
||||
// Manual close
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', function() {
|
||||
dismissMessage(message);
|
||||
});
|
||||
}
|
||||
|
||||
// Auto dismiss after delay
|
||||
setTimeout(function() {
|
||||
dismissMessage(message);
|
||||
}, AUTO_DISMISS_DELAY);
|
||||
|
||||
// Pause auto-dismiss on hover
|
||||
message.addEventListener('mouseenter', function() {
|
||||
message.classList.add('paused');
|
||||
});
|
||||
|
||||
message.addEventListener('mouseleave', function() {
|
||||
message.classList.remove('paused');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dismissMessage(message) {
|
||||
if (message.classList.contains('paused')) {
|
||||
// Retry after a short delay if paused
|
||||
setTimeout(function() {
|
||||
dismissMessage(message);
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
message.classList.add('fade-out');
|
||||
|
||||
setTimeout(function() {
|
||||
message.remove();
|
||||
|
||||
// Remove container if empty
|
||||
const container = document.querySelector('[data-testid="flash-container"]');
|
||||
if (container && container.children.length === 0) {
|
||||
container.remove();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initFlashMessages);
|
||||
} else {
|
||||
initFlashMessages();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user