✨ Story 3.5: projets secondaires
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Ready for Dev
|
review
|
||||||
|
|
||||||
## Story
|
## Story
|
||||||
|
|
||||||
@@ -20,20 +20,20 @@ Ready for Dev
|
|||||||
|
|
||||||
## Tasks / Subtasks
|
## Tasks / Subtasks
|
||||||
|
|
||||||
- [] **Task 1 : Ajouter la section dans projects.php** (AC: 1, 5)
|
- [x] **Task 1 : Ajouter la section dans projects.php** (AC: 1, 5)
|
||||||
- [] Récupérer les projets secondaires
|
- [x] Récupérer les projets secondaires
|
||||||
- [] Ajouter un titre de section "Autres projets"
|
- [x] Ajouter un titre de section "Autres projets"
|
||||||
- [] Ajouter un séparateur visuel
|
- [x] Ajouter un séparateur visuel
|
||||||
|
|
||||||
- [] **Task 2 : Créer le template project-card-compact.php** (AC: 2, 3)
|
- [x] **Task 2 : Créer le template project-card-compact.php** (AC: 2, 3)
|
||||||
- [] Format liste horizontale
|
- [x] Format liste horizontale
|
||||||
- [] Titre cliquable (si URL)
|
- [x] Titre cliquable (si URL)
|
||||||
- [] Description courte (truncate si nécessaire)
|
- [x] Description courte (truncate si nécessaire)
|
||||||
- [] Badges technologies (3 max)
|
- [x] Badges technologies (3 max)
|
||||||
|
|
||||||
- [] **Task 3 : Gérer les liens** (AC: 4)
|
- [x] **Task 3 : Gérer les liens** (AC: 4)
|
||||||
- [] Si URL → lien externe (nouvel onglet)
|
- [x] Si URL → lien externe (nouvel onglet)
|
||||||
- [] Si pas d'URL → texte simple
|
- [x] Si pas d'URL → texte simple
|
||||||
|
|
||||||
## Dev Notes
|
## Dev Notes
|
||||||
|
|
||||||
@@ -143,20 +143,22 @@ $shortContext = strlen($context) > 100
|
|||||||
## Dev Agent Record
|
## Dev Agent Record
|
||||||
|
|
||||||
### Agent Model Used
|
### Agent Model Used
|
||||||
Claude Opus 4.5 (claude-opus-4-5-20251101)
|
GPT-5 Codex
|
||||||
|
|
||||||
### File List
|
### File List
|
||||||
| File | Action | Description |
|
| File | Action | Description |
|
||||||
|------|--------|-------------|
|
|------|--------|-------------|
|
||||||
| `pages/projects.php` | Modified | Ajout section projets secondaires |
|
| `pages/projects.php` | Modified | Ajout section projets secondaires |
|
||||||
| `templates/project-card-compact.php` | Created | Template carte compacte |
|
| `templates/project-card-compact.php` | Created | Template carte compacte |
|
||||||
|
| `tests/projects-secondary.test.php` | Created | Tests projets secondaires |
|
||||||
|
| `tests/run.ps1` | Modified | Ajout tests secondaires |
|
||||||
|
|
||||||
### Completion Notes
|
### Completion Notes
|
||||||
- Section "Autres projets" avec séparateur visuel (hr)
|
- Section "Autres projets" avec séparateur visuel (hr)
|
||||||
- Template compact: titre + description tronquée (100 chars) + badges (3 max)
|
- Template compact: titre + description tronquée (100 chars) + badges (3 max)
|
||||||
- Lien externe avec icône SVG si URL disponible
|
- Lien externe avec icône SVG si URL disponible
|
||||||
- rel="noopener" pour sécurité
|
- rel="noopener" pour sécurité
|
||||||
- 1 projet secondaire affiché: "Site Vitrine Restaurant"
|
- Tests: `powershell -ExecutionPolicy Bypass -File tests/run.ps1`
|
||||||
|
|
||||||
### Debug Log References
|
### Debug Log References
|
||||||
Aucun problème rencontré.
|
Aucun problème rencontré.
|
||||||
@@ -166,4 +168,4 @@ Aucun problème rencontré.
|
|||||||
| Date | Version | Description | Author |
|
| Date | Version | Description | Author |
|
||||||
|------|---------|-------------|--------|
|
|------|---------|-------------|--------|
|
||||||
| 2026-01-22 | 0.1 | Création initiale | Sarah (PO) |
|
| 2026-01-22 | 0.1 | Création initiale | Sarah (PO) |
|
||||||
| 2026-01-23 | 1.0 | Implémentation complète | James (Dev) |
|
| 2026-02-04 | 1.0 | Implémentation complète | Amelia |
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ $pageDescription = 'Découvrez mes réalisations web : sites vitrines, e-commerc
|
|||||||
$currentPage = 'projects';
|
$currentPage = 'projects';
|
||||||
|
|
||||||
$featuredProjects = getProjectsByCategory('vedette');
|
$featuredProjects = getProjectsByCategory('vedette');
|
||||||
|
$secondaryProjects = getProjectsByCategory('secondaire');
|
||||||
|
|
||||||
include_template('header', compact('pageTitle', 'pageDescription'));
|
include_template('header', compact('pageTitle', 'pageDescription'));
|
||||||
include_template('navbar', compact('currentPage'));
|
include_template('navbar', compact('currentPage'));
|
||||||
@@ -30,6 +31,19 @@ include_template('navbar', compact('currentPage'));
|
|||||||
Projets à venir...
|
Projets à venir...
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($secondaryProjects)): ?>
|
||||||
|
<hr class="border-border my-16">
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 class="text-heading mb-8">Autres projets</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<?php foreach ($secondaryProjects as $project): ?>
|
||||||
|
<?php include_template('project-card-compact', ['project' => $project]); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
54
templates/project-card-compact.php
Normal file
54
templates/project-card-compact.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Carte projet compacte (projets secondaires)
|
||||||
|
* @param array $project Données du projet
|
||||||
|
*/
|
||||||
|
|
||||||
|
$title = $project['title'] ?? 'Sans titre';
|
||||||
|
$context = $project['context'] ?? '';
|
||||||
|
$url = $project['url'] ?? null;
|
||||||
|
$technologies = $project['technologies'] ?? [];
|
||||||
|
$maxTechs = 3;
|
||||||
|
|
||||||
|
$shortContext = strlen($context) > 100
|
||||||
|
? substr($context, 0, 100) . '...'
|
||||||
|
: $context;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article class="card hover:border-border transition-colors">
|
||||||
|
<div class="card-body flex flex-col sm:flex-row sm:items-center gap-4">
|
||||||
|
<div class="flex-grow">
|
||||||
|
<?php if ($url): ?>
|
||||||
|
<a href="<?= htmlspecialchars($url, ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
class="text-lg font-semibold text-text-primary hover:text-primary transition-colors inline-flex items-center gap-2">
|
||||||
|
<?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<h3 class="text-lg font-semibold text-text-primary">
|
||||||
|
<?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
</h3>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($shortContext): ?>
|
||||||
|
<p class="text-text-secondary text-sm mt-1">
|
||||||
|
<?= htmlspecialchars($shortContext, ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-2 sm:flex-shrink-0">
|
||||||
|
<?php foreach (array_slice($technologies, 0, $maxTechs) as $tech): ?>
|
||||||
|
<span class="badge text-xs"><?= htmlspecialchars($tech, ENT_QUOTES, 'UTF-8') ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php if (count($technologies) > $maxTechs): ?>
|
||||||
|
<span class="badge badge-muted text-xs">+<?= count($technologies) - $maxTechs ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
24
tests/projects-secondary.test.php
Normal file
24
tests/projects-secondary.test.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../includes/functions.php';
|
||||||
|
|
||||||
|
function assertTrue($cond, $msg) {
|
||||||
|
if (!$cond) {
|
||||||
|
fwrite(STDERR, $msg . PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$secondary = getProjectsByCategory('secondaire');
|
||||||
|
assertTrue(count($secondary) >= 1, 'expected secondary projects');
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
foreach ($secondary as $project) {
|
||||||
|
include __DIR__ . '/../templates/project-card-compact.php';
|
||||||
|
}
|
||||||
|
$html = ob_get_clean();
|
||||||
|
|
||||||
|
assertTrue(strpos($html, 'Autres projets') === false, 'template should not include section title');
|
||||||
|
assertTrue(strpos($html, 'badge') !== false, 'missing tech badges');
|
||||||
|
assertTrue(strpos($html, 'target="_blank"') !== false, 'missing external link');
|
||||||
|
|
||||||
|
fwrite(STDOUT, "OK\n");
|
||||||
@@ -13,4 +13,5 @@ php (Join-Path $here 'projects.test.php')
|
|||||||
php (Join-Path $here 'router.test.php')
|
php (Join-Path $here 'router.test.php')
|
||||||
php (Join-Path $here 'projects-list.test.php')
|
php (Join-Path $here 'projects-list.test.php')
|
||||||
php (Join-Path $here 'project-single.test.php')
|
php (Join-Path $here 'project-single.test.php')
|
||||||
|
php (Join-Path $here 'projects-secondary.test.php')
|
||||||
'OK'
|
'OK'
|
||||||
Reference in New Issue
Block a user