Fix blueprint naming and add missing templates

This commit is contained in:
2025-09-21 21:33:04 +02:00
parent 7ec30b8d5e
commit 5bdc5271a0
7 changed files with 497 additions and 7 deletions

6
app.py
View File

@@ -5,14 +5,14 @@
# Enhanced Quart Application with Database and Authentication # Enhanced Quart Application with Database and Authentication
import asyncio import asyncio
from quart import Quart, send_from_directory, session, g from quart import Quart, send_from_directory, session, g, render_template
from config import config from config import config
from models.database import init_database, db_manager from models.database import init_database, db_manager
from utils.helpers import get_flash_messages from utils.helpers import get_flash_messages
from utils.auth import get_current_user from utils.auth import get_current_user
# Import Blueprints # Import Blueprints
from routes.home import route_home from routes.home import home_bp
from routes.auth import auth_bp from routes.auth import auth_bp
from routes.dashboard import dashboard_bp from routes.dashboard import dashboard_bp
@@ -54,7 +54,7 @@ async def robots():
return await send_from_directory(app.static_folder, 'robots.txt') return await send_from_directory(app.static_folder, 'robots.txt')
# Register Blueprints # Register Blueprints
app.register_blueprint(route_home) app.register_blueprint(home_bp)
app.register_blueprint(auth_bp) app.register_blueprint(auth_bp)
app.register_blueprint(dashboard_bp) app.register_blueprint(dashboard_bp)

View File

@@ -2,11 +2,56 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright Hersel Giannella # Copyright Hersel Giannella
# Home Routes
from quart import Blueprint, render_template from quart import Blueprint, render_template
from models.project import Project
from models.settings import Settings
route_home = Blueprint('route_home', __name__) # Blueprint with correct name
home_bp = Blueprint('home', __name__)
@route_home.route('/') @home_bp.route('/')
async def home(): async def index():
return await render_template('index.html') """Homepage with featured projects"""
# Get featured projects
featured_projects = await Project.get_featured(limit=6)
# Get site settings
site_name = await Settings.get('site_name', 'Hersel.it')
site_description = await Settings.get('site_description', 'Portfolio personale di Hersel Giannella')
return await render_template('home/index.html',
featured_projects=featured_projects,
site_name=site_name,
site_description=site_description)
@home_bp.route('/progetti')
async def projects():
"""Projects page"""
# Get all published projects
projects = await Project.get_all(published_only=True, limit=50)
return await render_template('home/projects.html', projects=projects)
@home_bp.route('/progetto/<slug>')
async def project_detail(slug):
"""Single project page"""
project = await Project.find_by_slug(slug)
if not project:
return await render_template('errors/404.html'), 404
return await render_template('home/project_detail.html', project=project)
@home_bp.route('/about')
async def about():
"""About page"""
return await render_template('home/about.html')
@home_bp.route('/contatti')
async def contact():
"""Contact page"""
return await render_template('home/contact.html')
# Keep backward compatibility
route_home = home_bp

100
templates/auth/profile.html Normal file
View File

@@ -0,0 +1,100 @@
{% extends "base.html" %}
{% block title %}Il Mio Profilo - Hersel.it{% endblock %}
{% block content %}
<div class="container mt-5">
<div class="row">
<div class="col-lg-4">
<div class="card">
<div class="card-body text-center">
<div class="bg-primary bg-opacity-10 rounded-circle p-4 d-inline-block mb-3">
<i class="bi bi-person-circle display-3 text-primary"></i>
</div>
<h4>{{ user.full_name }}</h4>
<p class="text-muted">@{{ user.username }}</p>
{% if user.is_admin %}
<span class="badge bg-danger">Amministratore</span>
{% else %}
<span class="badge bg-primary">Utente</span>
{% endif %}
</div>
</div>
</div>
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h5 class="mb-0">Informazioni Profilo</h5>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-sm-3">
<strong>Username:</strong>
</div>
<div class="col-sm-9">
{{ user.username }}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3">
<strong>Email:</strong>
</div>
<div class="col-sm-9">
{{ user.email }}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3">
<strong>Nome Completo:</strong>
</div>
<div class="col-sm-9">
{{ user.full_name }}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3">
<strong>Ruolo:</strong>
</div>
<div class="col-sm-9">
{% if user.is_admin %}
<span class="badge bg-danger">Amministratore</span>
{% else %}
<span class="badge bg-primary">Utente</span>
{% endif %}
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3">
<strong>Registrato il:</strong>
</div>
<div class="col-sm-9">
{{ user.created_at.strftime('%d/%m/%Y alle %H:%M') if user.created_at else 'N/D' }}
</div>
</div>
<hr>
<div class="d-flex gap-2">
{% if user.is_admin %}
<a href="{{ url_for('dashboard.index') }}" class="btn btn-primary">
<i class="bi bi-speedometer2"></i> Dashboard
</a>
{% endif %}
<button class="btn btn-outline-primary" onclick="alert('Funzione in sviluppo')">
<i class="bi bi-pencil"></i> Modifica Profilo
</button>
<a href="{{ url_for('auth.logout') }}" class="btn btn-outline-danger">
<i class="bi bi-box-arrow-right"></i> Logout
</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

28
templates/errors/404.html Normal file
View File

@@ -0,0 +1,28 @@
{% extends "base.html" %}
{% block title %}Pagina Non Trovata - Hersel.it{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-6 text-center py-5">
<div class="py-5">
<i class="bi bi-exclamation-triangle-fill display-1 text-warning"></i>
<h1 class="display-4 fw-bold mt-4">404</h1>
<h2 class="mb-4">Pagina Non Trovata</h2>
<p class="lead text-muted mb-4">
Spiacente, la pagina che stai cercando non esiste o è stata spostata.
</p>
<div class="d-flex gap-3 justify-content-center">
<a href="{{ url_for('home.index') }}" class="btn btn-primary">
<i class="bi bi-house"></i> Torna alla Home
</a>
<a href="{{ url_for('home.projects') }}" class="btn btn-outline-primary">
<i class="bi bi-folder"></i> Vedi i Progetti
</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

29
templates/errors/500.html Normal file
View File

@@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block title %}Errore del Server - Hersel.it{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-6 text-center py-5">
<div class="py-5">
<i class="bi bi-exclamation-octagon-fill display-1 text-danger"></i>
<h1 class="display-4 fw-bold mt-4">500</h1>
<h2 class="mb-4">Errore del Server</h2>
<p class="lead text-muted mb-4">
Si è verificato un errore interno del server.
Il problema è stato segnalato e verrà risolto al più presto.
</p>
<div class="d-flex gap-3 justify-content-center">
<a href="{{ url_for('home.index') }}" class="btn btn-primary">
<i class="bi bi-house"></i> Torna alla Home
</a>
<a href="javascript:history.back()" class="btn btn-outline-primary">
<i class="bi bi-arrow-left"></i> Torna Indietro
</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

213
templates/home/index.html Normal file
View File

@@ -0,0 +1,213 @@
{% extends "base.html" %}
{% block title %}{{ site_name }} - {{ site_description }}{% endblock %}
{% block content %}
<!-- Hero Section -->
<section class="bg-primary text-white py-5">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-8">
<h1 class="display-4 fw-bold">Ciao, sono Hersel Giannella</h1>
<p class="lead mb-4">{{ site_description }}</p>
<div class="d-flex gap-3">
<a href="#progetti" class="btn btn-light btn-lg">
<i class="bi bi-folder"></i> I Miei Progetti
</a>
<a href="{{ url_for('home.contact') }}" class="btn btn-outline-light btn-lg">
<i class="bi bi-envelope"></i> Contattami
</a>
</div>
</div>
<div class="col-lg-4 text-center">
<div class="bg-white bg-opacity-10 rounded-circle p-4 d-inline-block">
<i class="bi bi-code-slash display-1"></i>
</div>
</div>
</div>
</div>
</section>
<!-- Featured Projects Section -->
<section id="progetti" class="py-5">
<div class="container">
<div class="text-center mb-5">
<h2 class="fw-bold">Progetti in Evidenza</h2>
<p class="text-muted">Alcuni dei miei lavori più interessanti</p>
</div>
{% if featured_projects %}
<div class="row g-4">
{% for project in featured_projects %}
<div class="col-lg-4 col-md-6">
<div class="card h-100 shadow-sm hover-card">
{% if project.image_url %}
<img src="{{ project.image_url }}" class="card-img-top" alt="{{ project.title }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-light d-flex align-items-center justify-content-center" style="height: 200px;">
<i class="bi bi-folder display-4 text-muted"></i>
</div>
{% endif %}
<div class="card-body">
<h5 class="card-title">{{ project.title }}</h5>
<p class="card-text text-muted">{{ project.description[:100] }}{% if project.description|length > 100 %}...{% endif %}</p>
{% if project.technologies %}
<div class="mb-3">
{% for tech in project.technologies[:3] %}
<span class="badge bg-secondary me-1">{{ tech }}</span>
{% endfor %}
{% if project.technologies|length > 3 %}
<span class="badge bg-light text-dark">+{{ project.technologies|length - 3 }}</span>
{% endif %}
</div>
{% endif %}
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<a href="{{ url_for('home.project_detail', slug=project.slug) }}" class="btn btn-sm btn-primary">
<i class="bi bi-eye"></i> Dettagli
</a>
{% if project.github_url %}
<a href="{{ project.github_url }}" target="_blank" class="btn btn-sm btn-outline-primary">
<i class="bi bi-github"></i> GitHub
</a>
{% endif %}
</div>
{% if project.demo_url %}
<a href="{{ project.demo_url }}" target="_blank" class="btn btn-sm btn-success">
<i class="bi bi-box-arrow-up-right"></i> Demo
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="text-center mt-5">
<a href="{{ url_for('home.projects') }}" class="btn btn-outline-primary btn-lg">
<i class="bi bi-folder"></i> Vedi Tutti i Progetti
</a>
</div>
{% else %}
<div class="text-center py-5">
<i class="bi bi-folder2-open display-1 text-muted"></i>
<h4 class="mt-3">Progetti in arrivo</h4>
<p class="text-muted">Sto lavorando su alcuni progetti interessanti!</p>
</div>
{% endif %}
</div>
</section>
<!-- Skills Section -->
<section class="bg-light py-5">
<div class="container">
<div class="text-center mb-5">
<h2 class="fw-bold">Le Mie Competenze</h2>
<p class="text-muted">Tecnologie e strumenti che utilizzo</p>
</div>
<div class="row g-4">
<div class="col-lg-3 col-md-6">
<div class="text-center">
<div class="bg-primary bg-opacity-10 rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-code-slash fs-1 text-primary"></i>
</div>
<h5>Backend Development</h5>
<p class="text-muted">Python, Quart, Flask, FastAPI</p>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="text-center">
<div class="bg-success bg-opacity-10 rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-palette fs-1 text-success"></i>
</div>
<h5>Frontend Development</h5>
<p class="text-muted">HTML, CSS, JavaScript, Bootstrap</p>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="text-center">
<div class="bg-warning bg-opacity-10 rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-database fs-1 text-warning"></i>
</div>
<h5>Database</h5>
<p class="text-muted">MySQL, PostgreSQL, MongoDB</p>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="text-center">
<div class="bg-info bg-opacity-10 rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-tools fs-1 text-info"></i>
</div>
<h5>DevOps & Tools</h5>
<p class="text-muted">Docker, Git, Linux, CI/CD</p>
</div>
</div>
</div>
</div>
</section>
<!-- Contact Section -->
<section id="contatti" class="py-5">
<div class="container">
<div class="text-center mb-5">
<h2 class="fw-bold">Parliamo del Tuo Progetto</h2>
<p class="text-muted">Sono sempre interessato a nuove opportunità e collaborazioni</p>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="row g-4">
<div class="col-md-4 text-center">
<div class="bg-primary bg-opacity-10 rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-envelope fs-2 text-primary"></i>
</div>
<h6>Email</h6>
<a href="mailto:info@hersel.it" class="text-decoration-none">info@hersel.it</a>
</div>
<div class="col-md-4 text-center">
<div class="bg-dark rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-github fs-2 text-white"></i>
</div>
<h6>GitHub</h6>
<a href="https://github.com/BluLupo" target="_blank" class="text-decoration-none">BluLupo</a>
</div>
<div class="col-md-4 text-center">
<div class="bg-info bg-opacity-10 rounded-circle p-3 d-inline-block mb-3">
<i class="bi bi-linkedin fs-2 text-info"></i>
</div>
<h6>LinkedIn</h6>
<a href="#" target="_blank" class="text-decoration-none">Hersel Giannella</a>
</div>
</div>
<div class="text-center mt-5">
<a href="{{ url_for('home.contact') }}" class="btn btn-primary btn-lg">
<i class="bi bi-chat-dots"></i> Inizia una Conversazione
</a>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
{% block extra_head %}
<style>
.hover-card {
transition: transform 0.2s;
}
.hover-card:hover {
transform: translateY(-5px);
}
</style>
{% endblock %}

View File

@@ -0,0 +1,75 @@
{% extends "base.html" %}
{% block title %}Progetti - Hersel.it{% endblock %}
{% block content %}
<div class="container py-5">
<div class="text-center mb-5">
<h1 class="fw-bold">I Miei Progetti</h1>
<p class="lead text-muted">Una raccolta dei lavori che ho realizzato</p>
</div>
{% if projects %}
<div class="row g-4">
{% for project in projects %}
<div class="col-lg-4 col-md-6">
<div class="card h-100 shadow-sm">
{% if project.image_url %}
<img src="{{ project.image_url }}" class="card-img-top" alt="{{ project.title }}" style="height: 200px; object-fit: cover;">
{% else %}
<div class="card-img-top bg-light d-flex align-items-center justify-content-center" style="height: 200px;">
<i class="bi bi-folder display-4 text-muted"></i>
</div>
{% endif %}
<div class="card-body d-flex flex-column">
<div class="mb-auto">
<h5 class="card-title">{{ project.title }}</h5>
<p class="card-text text-muted">{{ project.description[:150] }}{% if project.description|length > 150 %}...{% endif %}</p>
{% if project.technologies %}
<div class="mb-3">
{% for tech in project.technologies[:4] %}
<span class="badge bg-secondary me-1 mb-1">{{ tech }}</span>
{% endfor %}
{% if project.technologies|length > 4 %}
<span class="badge bg-light text-dark">+{{ project.technologies|length - 4 }}</span>
{% endif %}
</div>
{% endif %}
</div>
<div class="d-flex justify-content-between align-items-center mt-3">
<div class="btn-group">
<a href="{{ url_for('home.project_detail', slug=project.slug) }}" class="btn btn-sm btn-primary">
<i class="bi bi-eye"></i> Dettagli
</a>
{% if project.github_url %}
<a href="{{ project.github_url }}" target="_blank" class="btn btn-sm btn-outline-primary">
<i class="bi bi-github"></i> Codice
</a>
{% endif %}
</div>
{% if project.demo_url %}
<a href="{{ project.demo_url }}" target="_blank" class="btn btn-sm btn-success">
<i class="bi bi-box-arrow-up-right"></i> Demo Live
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<i class="bi bi-folder2-open display-1 text-muted"></i>
<h4 class="mt-3">Nessun progetto disponibile</h4>
<p class="text-muted">Sto lavorando su alcuni progetti interessanti!</p>
<a href="{{ url_for('home.index') }}" class="btn btn-primary">
<i class="bi bi-arrow-left"></i> Torna alla Home
</a>
</div>
{% endif %}
</div>
{% endblock %}