Fix blueprint naming and add missing templates
This commit is contained in:
6
app.py
6
app.py
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
100
templates/auth/profile.html
Normal 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
28
templates/errors/404.html
Normal 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
29
templates/errors/500.html
Normal 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
213
templates/home/index.html
Normal 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 %}
|
||||||
75
templates/home/projects.html
Normal file
75
templates/home/projects.html
Normal 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 %}
|
||||||
Reference in New Issue
Block a user