- 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
112 lines
2.7 KiB
HTML
112 lines
2.7 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ error_code }} - {{ error_title }}{% endblock %}
|
|
{% block meta_description %}{{ error_message }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="error-page" data-testid="error-page">
|
|
<div class="error-content" data-testid="error-content">
|
|
<div class="error-icon" data-testid="error-icon">
|
|
{% if error_code == 404 %}
|
|
🔍
|
|
{% elif error_code == 403 %}
|
|
🚫
|
|
{% elif error_code == 500 %}
|
|
⚠️
|
|
{% else %}
|
|
❌
|
|
{% endif %}
|
|
</div>
|
|
|
|
<h1 class="error-code" data-testid="error-code">{{ error_code }}</h1>
|
|
<h2 class="error-title" data-testid="error-title">{{ error_title }}</h2>
|
|
<p class="error-message" data-testid="error-message">{{ error_message }}</p>
|
|
|
|
<div class="error-actions" data-testid="error-actions">
|
|
<a href="/" class="btn btn-primary" data-testid="btn-error-home">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 0.5rem;">
|
|
<path d="M2 8L8 2L14 8M4 6V13H12V6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
Go Home
|
|
</a>
|
|
|
|
{% if error_code == 403 %}
|
|
<a href="/auth/login" class="btn" data-testid="btn-error-login">
|
|
Sign In
|
|
</a>
|
|
{% endif %}
|
|
|
|
<button onclick="window.history.back()" class="btn btn-ghost" data-testid="btn-error-back">
|
|
Go Back
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.error-page {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 60vh;
|
|
padding: 2rem 1rem;
|
|
}
|
|
|
|
.error-content {
|
|
text-align: center;
|
|
max-width: 500px;
|
|
}
|
|
|
|
.error-icon {
|
|
font-size: 5rem;
|
|
margin-bottom: 1.5rem;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.error-code {
|
|
font-size: 6rem;
|
|
font-weight: 700;
|
|
color: var(--color-primary);
|
|
margin: 0;
|
|
line-height: 1;
|
|
}
|
|
|
|
.error-title {
|
|
font-size: 1.5rem;
|
|
color: var(--color-text-dark);
|
|
margin: 1rem 0 0.5rem;
|
|
}
|
|
|
|
.error-message {
|
|
color: var(--color-text-light);
|
|
font-size: 1.125rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.error-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
justify-content: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.error-code {
|
|
font-size: 4rem;
|
|
}
|
|
|
|
.error-icon {
|
|
font-size: 3.5rem;
|
|
}
|
|
|
|
.error-actions {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.error-actions .btn {
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|