Initial commit

This commit is contained in:
2026-03-31 13:10:16 +02:00
commit 0d080a9b77
59 changed files with 4021 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
{% extends "base.html" %}
{% load static %}
{% block title %}{{ project.title }} — {{ config.seo.site_title }}{% endblock %}
{% block content %}
<!-- ─── En-tête projet ───────────────────────────────────────────────────── -->
<section class="project-hero">
<div class="project-hero-container">
<nav class="breadcrumb">
<a href="{% url 'projects:home' %}">Accueil</a>
<span class="breadcrumb-sep"></span>
<a href="{% url 'projects:list' %}">Projets</a>
<span class="breadcrumb-sep"></span>
<span>{{ project.title }}</span>
</nav>
<div class="project-hero-content">
<div class="project-meta-top">
<span class="project-category-badge">{{ project.category }}</span>
{% if project.context %}<span class="project-context-badge">{{ project.context }}</span>{% endif %}
{% if project.complexity %}<span class="complexity-badge complexity-{{ project.complexity|lower }}">{{ project.complexity }}</span>{% endif %}
</div>
<h1 class="project-hero-title">{{ project.title }}</h1>
<p class="project-hero-desc">{{ project.short_description }}</p>
<div class="project-techs-header">
{% for tech in project.technologies %}
<span class="tech-tag tech-tag-lg">{{ tech }}</span>
{% endfor %}
</div>
{% if project.github_url or project.demo_url %}
<div class="project-links">
{% if project.github_url %}
<a href="{{ project.github_url }}" target="_blank" class="btn btn-outline btn-sm">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z"/></svg>
Voir le code
</a>
{% endif %}
{% if project.demo_url %}
<a href="{{ project.demo_url }}" target="_blank" class="btn btn-primary btn-sm">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
Voir la démo
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
</section>
<!-- ─── Contenu détaillé ─────────────────────────────────────────────────── -->
<section class="section">
<div class="detail-container">
<div class="detail-main">
<!-- Galerie images -->
{% if project.images %}
<div class="gallery-section">
<h2 class="detail-section-title">Galerie</h2>
<div class="gallery-grid">
{% for img in project.images %}
<div class="gallery-item" onclick="openLightbox('{{ img }}')">
<img src="{{ img }}" alt="{{ project.title }} — image {{ forloop.counter }}" loading="lazy">
<div class="gallery-overlay">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Problématique & Solution -->
{% if project.problem or project.solution %}
<div class="problem-solution-grid">
{% if project.problem %}
<div class="ps-card ps-problem">
<div class="ps-icon"></div>
<h3 class="ps-title">Problématique</h3>
<p class="ps-text">{{ project.problem }}</p>
</div>
{% endif %}
{% if project.solution %}
<div class="ps-card ps-solution">
<div class="ps-icon"></div>
<h3 class="ps-title">Solution apportée</h3>
<p class="ps-text">{{ project.solution }}</p>
</div>
{% endif %}
</div>
{% endif %}
<!-- Description complète -->
<div class="description-section">
<h2 class="detail-section-title">Description du projet</h2>
<div class="description-content">
{{ project.full_description|linebreaks }}
</div>
</div>
<!-- Résultat -->
{% if project.outcome %}
<div class="outcome-section">
<h2 class="detail-section-title">Résultat</h2>
<div class="outcome-card">
<span class="outcome-icon">🎯</span>
<p>{{ project.outcome }}</p>
</div>
</div>
{% endif %}
</div>
<!-- ─── Sidebar ──────────────────────────────────────────────────── -->
<aside class="detail-sidebar">
<!-- Infos clés -->
<div class="sidebar-card">
<h3 class="sidebar-card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Informations
</h3>
<ul class="info-list">
{% if project.context %}
<li class="info-item"><span class="info-label">Contexte</span><span class="info-value">{{ project.context }}</span></li>
{% endif %}
{% if project.period %}
<li class="info-item"><span class="info-label">Période</span><span class="info-value">{{ project.period }}</span></li>
{% endif %}
{% if project.role %}
<li class="info-item"><span class="info-label">Rôle</span><span class="info-value">{{ project.role }}</span></li>
{% endif %}
{% if project.complexity %}
<li class="info-item"><span class="info-label">Complexité</span><span class="info-value">{{ project.complexity }}</span></li>
{% endif %}
</ul>
</div>
<!-- Points clés -->
{% if project.highlights %}
<div class="sidebar-card">
<h3 class="sidebar-card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
Points clés
</h3>
<ul class="highlights-list">
{% for highlight in project.highlights %}
<li class="highlight-item">
<span class="highlight-check"></span>
{{ highlight }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
<!-- Technologies -->
<div class="sidebar-card">
<h3 class="sidebar-card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
Technologies
</h3>
<div class="sidebar-techs">
{% for tech in project.technologies %}
<a href="{% url 'projects:list' %}?tech={{ tech }}" class="tech-tag tech-tag-clickable">{{ tech }}</a>
{% endfor %}
</div>
</div>
<!-- Catégorie -->
<div class="sidebar-card">
<h3 class="sidebar-card-title">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 20h16M4 4h16M9 9h6M9 15h6"/></svg>
Catégorie
</h3>
<a href="{% url 'projects:list' %}?category={{ project.category }}" class="category-link">
{{ project.category }}
</a>
</div>
</aside>
</div>
</section>
<!-- ─── Navigation projet précédent / suivant ────────────────────────────── -->
<section class="project-nav-section">
<div class="project-nav-container">
{% if prev_project %}
<a href="{% url 'projects:detail' prev_project.slug %}" class="project-nav-card project-nav-prev">
<span class="nav-direction">← Précédent</span>
<span class="nav-project-title">{{ prev_project.title }}</span>
</a>
{% else %}<div></div>{% endif %}
<a href="{% url 'projects:list' %}" class="btn btn-outline">Tous les projets</a>
{% if next_project %}
<a href="{% url 'projects:detail' next_project.slug %}" class="project-nav-card project-nav-next">
<span class="nav-direction">Suivant →</span>
<span class="nav-project-title">{{ next_project.title }}</span>
</a>
{% else %}<div></div>{% endif %}
</div>
</section>
<!-- ─── Lightbox ─────────────────────────────────────────────────────────── -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<button class="lightbox-close" onclick="closeLightbox()"></button>
<img class="lightbox-img" id="lightboxImg" src="" alt="">
</div>
{% endblock %}

View File

@@ -0,0 +1,167 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Projets — Portfolio Alexandre{% endblock %}
{% block content %}
<!-- ─── En-tête page projets ─────────────────────────────────────────────── -->
<section class="page-header">
<div class="page-header-container">
<span class="section-tag">Réalisations</span>
<h1 class="page-title">Mes Projets</h1>
<p class="page-sub">{{ total_count }} projet{{ total_count|pluralize }} — filtrez par technologie ou catégorie</p>
</div>
</section>
<!-- ─── Filtres ──────────────────────────────────────────────────────────── -->
<section class="filters-section">
<div class="filters-container">
<form method="GET" action="{% url 'projects:list' %}" class="filters-form" id="filtersForm">
<!-- Filtre catégorie -->
<div class="filter-group">
<label class="filter-label">Catégorie</label>
<div class="filter-pills" id="categoryPills">
<button type="button"
class="filter-pill {% if not selected_category %}active{% endif %}"
data-filter="category"
data-value="">
Toutes
</button>
{% for cat in categories %}
<button type="button"
class="filter-pill {% if selected_category == cat %}active{% endif %}{% if forloop.counter > 5 %} pill-hidden{% endif %}"
data-filter="category"
data-value="{{ cat }}"
{% if forloop.counter > 5 %}data-extra="true"{% endif %}>
{{ cat }}
</button>
{% endfor %}
{% if categories|length > 5 %}
<button type="button" class="filter-pill pill-more" data-target="categoryPills" data-total="{{ categories|length|add:'-5' }}">
+{{ categories|length|add:"-5" }} voir plus
</button>
{% endif %}
</div>
<input type="hidden" name="category" id="categoryInput" value="{{ selected_category }}">
</div>
<!-- Filtre technologie -->
<div class="filter-group">
<label class="filter-label">Technologie</label>
<div class="filter-pills" id="techPills">
<button type="button"
class="filter-pill {% if not selected_tech %}active{% endif %}"
data-filter="tech"
data-value="">
Toutes
</button>
{% for tech in technologies %}
<button type="button"
class="filter-pill {% if selected_tech == tech %}active{% endif %}{% if forloop.counter > 5 %} pill-hidden{% endif %}"
data-filter="tech"
data-value="{{ tech }}"
{% if forloop.counter > 5 %}data-extra="true"{% endif %}>
{{ tech }}
</button>
{% endfor %}
{% if technologies|length > 5 %}
<button type="button" class="filter-pill pill-more" data-target="techPills" data-total="{{ technologies|length|add:'-5' }}">
+{{ technologies|length|add:"-5" }} voir plus
</button>
{% endif %}
</div>
<input type="hidden" name="tech" id="techInput" value="{{ selected_tech }}">
</div>
{% if selected_category or selected_tech %}
<a href="{% url 'projects:list' %}" class="btn btn-ghost btn-sm">
✕ Réinitialiser les filtres
</a>
{% endif %}
</form>
</div>
</section>
<!-- ─── Grille projets ───────────────────────────────────────────────────── -->
<section class="section">
<div class="section-container">
{% if selected_category or selected_tech %}
<div class="filter-result-info">
<span>{{ total_count }} résultat{{ total_count|pluralize }}</span>
{% if selected_category %}<span class="filter-tag-active">{{ selected_category }}</span>{% endif %}
{% if selected_tech %}<span class="filter-tag-active">{{ selected_tech }}</span>{% endif %}
</div>
{% endif %}
<div class="projects-grid projects-grid-full" id="projectsGrid">
{% for project in projects %}
<div class="project-card">
<div class="card-image-wrapper">
{% if project.images %}
<img src="{{ project.images.0 }}" alt="{{ project.title }}" class="card-image" onerror="this.parentElement.classList.add('no-image')">
{% else %}
<div class="card-image-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
</div>
{% endif %}
<div class="card-category-badge">{{ project.category }}</div>
</div>
<div class="card-body">
<h3 class="card-title">{{ project.title }}</h3>
<p class="card-desc">{{ project.short_description }}</p>
<div class="card-techs">
{% for tech in project.technologies|slice:":5" %}
<span class="tech-tag">{{ tech }}</span>
{% endfor %}
{% if project.technologies|length > 5 %}
<span class="tech-tag tech-tag-more">+{{ project.technologies|length|add:"-5" }}</span>
{% endif %}
</div>
<a href="{% url 'projects:detail' project.slug %}" class="card-link">
Voir le projet
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
</a>
</div>
</div>
{% empty %}
<div class="empty-state-container">
<div class="empty-icon">🔍</div>
<h3>Aucun projet trouvé</h3>
<p>Essayez de modifier vos filtres ou <a href="{% url 'projects:list' %}">réinitialisez</a>.</p>
</div>
{% endfor %}
</div>
</div>
</section>
{% endblock %}
{% block extra_js %}
<script>
document.querySelectorAll('.pill-more').forEach(btn => {
const container = document.getElementById(btn.dataset.target);
// Sélectionne uniquement les pills "extra" (au-delà des 5 premières)
const extraPills = container.querySelectorAll('.pill-hidden[data-filter]');
const total = parseInt(btn.dataset.total || extraPills.length);
btn.addEventListener('click', () => {
const isExpanded = btn.dataset.expanded === 'true';
if (!isExpanded) {
container.querySelectorAll('.pill-hidden[data-filter]').forEach(p => p.classList.remove('pill-hidden'));
btn.textContent = 'voir moins ↑';
btn.classList.add('pill-less');
btn.dataset.expanded = 'true';
} else {
container.querySelectorAll('.filter-pill[data-extra="true"]').forEach(p => p.classList.add('pill-hidden'));
btn.textContent = '+' + total + ' voir plus';
btn.classList.remove('pill-less');
btn.dataset.expanded = 'false';
}
});
});
</script>
{% endblock %}