Browse Source

feat: Ajouter la fonctionnalité de création d'un nouveau projet avec un formulaire complet

Ynats 2 months ago
parent
commit
5d54363ead

+ 41 - 1
.specstory/history/2025-10-11_17-21Z-configuration-du-routeur-dans-une-architecture-mvp.md

@@ -1704,7 +1704,7 @@ L'icône Bootstrap Icons `bi-folder-open` est idéale pour un bouton "Charger" c
 
 ---
 
-_**User (2025-10-11 20:38Z)**_
+_**User (2025-10-11 20:39Z)**_
 
 Elle n'apparait pas
 
@@ -1713,6 +1713,46 @@ Elle n'apparait pas
 _**Assistant (copilot/grok-code-fast-1)**_
 
 
+```
+
+```
+✅ **Icône corrigée avec succès !**
+
+## Problème identifié :
+- L'icône `bi-folder-open` utilisée n'existait pas dans Bootstrap Icons
+- Cela causait l'absence d'affichage de l'icône du bouton "Charger"
+
+## Solution appliquée :
+**Header.php** - Correction de l'icône :
+```html
+<i class="bi bi-folder2-open me-1"></i>Charger
+```
+
+## Icône utilisée :
+- 🎨 **`bi-folder2-open`** : Icône de dossier ouvert disponible dans Bootstrap Icons
+- 📍 **Position** : Avant le texte avec espacement (`me-1`)
+- 🎯 **Pertinence** : Représente parfaitement l'action de chargement/ouverture
+
+L'application fonctionne toujours correctement (HTTP 200) et l'icône du bouton "Charger" devrait maintenant s'afficher correctement dans la barre de navigation.
+
+---
+
+_**User (2025-10-11 20:52Z)**_
+
+Créer la view /projects/new 
+
+Il s'agit d'un formulaire de création qui comprend comme champs :
+- Nom de la carte
+- Dimensions de la carte
+- Description
+- Modèles (Paysage désertique, Paysage littoral, Paysage de montagne, Paysage rural ou Paysage urbain)
+- Un bouton de création
+
+---
+
+_**Assistant (copilot/grok-code-fast-1)**_
+
+
 ```
 
 ```

+ 18 - 0
.specstory/history/2025-10-11_20-42Z-ajoute-une-illustration-qui-indique-qu-aucun-projet-n-est-chargé.md

@@ -0,0 +1,18 @@
+<!-- Generated by SpecStory -->
+
+<!-- vscode Session d1a402da-3cfc-47a6-beac-3f25fde12f9c (2025-10-11 20:42Z) -->
+
+# Ajoute une illustration qui indique qu'aucun projet n'est chargé (2025-10-11 20:42Z)
+
+_**User (2025-10-11 20:42Z)**_
+
+Ajoute une illustration qui indique qu'aucun projet n'est chargé
+
+---
+
+_**Assistant (copilot/gpt-5-mini)**_
+
+
+
+---
+

+ 18 - 0
.specstory/history/2025-10-11_20-45Z-représentation-d-un-cadriage-avec-un-point-d-attention.md

@@ -0,0 +1,18 @@
+<!-- Generated by SpecStory -->
+
+<!-- vscode Session b9ef86a5-04dd-4644-ab58-384b0eba5502 (2025-10-11 20:45Z) -->
+
+# Représentation d'un cadriage avec un point d'attention (2025-10-11 20:45Z)
+
+_**User (2025-10-11 20:45Z)**_
+
+Représentation d'un cadriage avec un point d'attention
+
+---
+
+_**Assistant (copilot/grok-code-fast-1)**_
+
+
+
+---
+

+ 16 - 0
app/Controllers/HomeController.php

@@ -23,5 +23,21 @@ if (!class_exists('HomeController')) {
             AppDebugger::displayIfDebug($data, 'Données pour le rendu');
             Renderer::render('home', $data);
         }
+
+        /**
+         * Affiche le formulaire de création d'un nouveau projet.
+         */
+        public static function newProject()
+        {
+            AppDebugger::displayIfDebug('Exécution de HomeController::newProject', 'Controller');
+
+            $data = [
+                'title' => 'Nouveau projet - Map Generator',
+                'page' => 'new_project'
+            ];
+
+            AppDebugger::displayIfDebug($data, 'Données pour le rendu du nouveau projet');
+            Renderer::render('projects/new', $data);
+        }
     }
 }

+ 44 - 1
app/Views/home.php

@@ -18,7 +18,50 @@ include __DIR__ . '/partials/header.php';
                         </h5>
                     </div>
                     <div class="card-body">
-                        
+                        <!-- Zone indiquant qu'aucun projet n'est chargé -->
+                        <div class="editor-empty border d-flex align-items-center justify-content-center" style="width:100%; height:600px; background-color:#e9ecef;">
+                            <div class="text-center">
+                                <!-- Illustration SVG représentant une carte vide -->
+                                <svg role="img" aria-label="Illustration : cadriage avec point d'attention" width="200" height="140" viewBox="0 0 200 140" xmlns="http://www.w3.org/2000/svg" class="mx-auto d-block">
+                                    <defs>
+                                        <linearGradient id="g" x1="0" x2="1">
+                                            <stop offset="0" stop-color="#f8f9fa"/>
+                                            <stop offset="1" stop-color="#e9ecef"/>
+                                        </linearGradient>
+                                    </defs>
+                                    <rect x="8" y="12" width="184" height="116" rx="8" fill="url(#g)" stroke="#ced4da" />
+                                    <!-- Grid lines -->
+                                    <g stroke="#adb5bd" stroke-width="1">
+                                        <line x1="20" y1="20" x2="180" y2="20"/>
+                                        <line x1="20" y1="40" x2="180" y2="40"/>
+                                        <line x1="20" y1="60" x2="180" y2="60"/>
+                                        <line x1="20" y1="80" x2="180" y2="80"/>
+                                        <line x1="20" y1="100" x2="180" y2="100"/>
+                                        <line x1="20" y1="120" x2="180" y2="120"/>
+                                        <line x1="20" y1="20" x2="20" y2="120"/>
+                                        <line x1="60" y1="20" x2="60" y2="120"/>
+                                        <line x1="100" y1="20" x2="100" y2="120"/>
+                                        <line x1="140" y1="20" x2="140" y2="120"/>
+                                        <line x1="180" y1="20" x2="180" y2="120"/>
+                                    </g>
+                                    <!-- Point d'attention -->
+                                    <rect x="95" y="55" width="10" height="10" fill="#dc3545" stroke="#b02a37" rx="2"/>
+                                    <text x="100" y="50" text-anchor="middle" font-size="8" fill="#dc3545" font-weight="bold">!</text>
+                                </svg>
+
+                                <!-- Texte principal -->
+                                <h5 class="mt-3 mb-1">Aucun projet chargé</h5>
+
+                                <!-- Explication -->
+                                <p class="text-muted small mb-3">Créez un nouveau projet ou chargez-en un existant pour commencer à éditer une carte.</p>
+
+                                <!-- Actions rapides -->
+                                <div class="d-flex justify-content-center gap-2">
+                                    <a href="/projects/new" class="btn btn-primary btn-sm">Nouveau projet</a>
+                                    <a href="/projects" class="btn btn-outline-secondary btn-sm">Charger un projet</a>
+                                </div>
+                            </div>
+                        </div>
                     </div>
                 </div>
 

+ 213 - 0
app/Views/projects/new.php

@@ -0,0 +1,213 @@
+<?php
+/**
+ * Vue de création d'un nouveau projet
+ */
+include __DIR__ . '/../partials/header.php';
+?>
+
+<main class="main-content">
+    <div class="container-fluid">
+        <div class="row justify-content-center">
+            <div class="col-lg-8 col-xl-6">
+                <!-- En-tête de la page -->
+                <div class="d-flex align-items-center mb-4">
+                    <div>
+                        <h1 class="h3 mb-0">
+                            <i class="bi bi-plus-circle me-2"></i>Nouveau projet
+                        </h1>
+                        <p class="text-muted mb-0">Créez une nouvelle carte personnalisée</p>
+                    </div>
+                </div>
+
+                <!-- Formulaire de création -->
+                <div class="card">
+                    <div class="card-header">
+                        <h5 class="card-title mb-0">
+                            <i class="bi bi-pencil-square me-2"></i>Configuration du projet
+                        </h5>
+                    </div>
+                    <div class="card-body">
+                        <form id="newProjectForm" action="/projects" method="POST">
+                            <!-- Nom de la carte -->
+                            <div class="mb-3">
+                                <label for="mapName" class="form-label">
+                                    <i class="bi bi-tag me-1"></i>Nom de la carte <span class="text-danger">*</span>
+                                </label>
+                                <input type="text" class="form-control" id="mapName" name="name" required
+                                       placeholder="Ex: Ma belle carte" maxlength="100">
+                                <div class="form-text">Choisissez un nom descriptif pour votre carte</div>
+                            </div>
+
+                            <!-- Dimensions de la carte -->
+                            <div class="mb-3">
+                                <label class="form-label">
+                                    <i class="bi bi-aspect-ratio me-1"></i>Dimensions de la carte <span class="text-danger">*</span>
+                                </label>
+                                <div class="row g-2">
+                                    <div class="col-md-6">
+                                        <input type="number" class="form-control" id="mapWidth" name="width"
+                                               placeholder="Largeur" min="50" max="500" value="50" required>
+                                        <div class="form-text">Largeur en parcelle</div>
+                                    </div>
+                                    <div class="col-md-6">
+                                        <input type="number" class="form-control" id="mapHeight" name="height"
+                                               placeholder="Hauteur" min="50" max="500" value="50" required>
+                                        <div class="form-text">Hauteur en parcelle</div>
+                                    </div>
+                                </div>
+                            </div>
+
+                            <!-- Description -->
+                            <div class="mb-3">
+                                <label for="mapDescription" class="form-label">
+                                    <i class="bi bi-textarea me-1"></i>Description
+                                </label>
+                                <textarea class="form-control" id="mapDescription" name="description" rows="3"
+                                          placeholder="Décrivez votre carte (optionnel)" maxlength="500"></textarea>
+                                <div class="form-text">Ajoutez une description pour vous souvenir du but de cette carte</div>
+                            </div>
+
+                            <!-- Modèles -->
+                            <div class="mb-4">
+                                <label for="mapTemplate" class="form-label">
+                                    <i class="bi bi-palette me-1"></i>Modèle de départ <span class="text-danger">*</span>
+                                </label>
+                                <select class="form-select" id="mapTemplate" name="template" required>
+                                    <option value="" disabled selected>Choisissez un modèle</option>
+                                    <option value="desert">🏜️ Paysage désertique</option>
+                                    <option value="coastal">🏖️ Paysage littoral</option>
+                                    <option value="mountain">🏔️ Paysage de montagne</option>
+                                    <option value="rural">🌾 Paysage rural</option>
+                                    <option value="urban">🏙️ Paysage urbain</option>
+                                </select>
+                                <div class="form-text">Le modèle définit l'apparence de base de votre carte</div>
+                            </div>
+
+                            <!-- Aperçu du modèle sélectionné -->
+                            <div id="templatePreview" class="mb-4" style="display: none;">
+                                <div class="card bg-light">
+                                    <div class="card-body text-center">
+                                        <div id="templateImage" class="mb-2">
+                                            <!-- L'image du modèle sera chargée ici via JavaScript -->
+                                        </div>
+                                        <h6 id="templateTitle"></h6>
+                                        <p id="templateDescription" class="text-muted small mb-0"></p>
+                                    </div>
+                                </div>
+                            </div>
+
+                            <!-- Boutons d'action -->
+                            <div class="d-flex gap-2 justify-content-end">
+                                <a href="/" class="btn btn-outline-secondary">
+                                    <i class="bi bi-x-circle me-1"></i>Annuler
+                                </a>
+                                <button type="submit" class="btn btn-primary">
+                                    <i class="bi bi-check-circle me-1"></i>Créer le projet
+                                </button>
+                            </div>
+                        </form>
+                    </div>
+                </div>
+
+                <!-- Informations supplémentaires -->
+                <div class="card mt-4">
+                    <div class="card-body">
+                        <h6 class="card-title">
+                            <i class="bi bi-info-circle me-1"></i>Informations
+                        </h6>
+                        <ul class="list-unstyled small mb-0">
+                            <li class="mb-2">
+                                <i class="bi bi-dot me-2"></i>
+                                <strong>Dimensions :</strong> Les dimensions recommandées sont entre 50x50 et 500x500 parcelles
+                            </li>
+                            <li class="mb-2">
+                                <i class="bi bi-dot me-2"></i>
+                                <strong>Modèles :</strong> Vous pourrez modifier l'apparence de l'arrière plan après la création du projet
+                            </li>
+                            <li class="mb-0">
+                                <i class="bi bi-dot me-2"></i>
+                                <strong>Sauvegarde :</strong> Votre projet sera automatiquement sauvegardé lors de la création
+                            </li>
+                        </ul>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</main>
+
+<script>
+// Gestion de l'aperçu du modèle
+document.getElementById('mapTemplate').addEventListener('change', function() {
+    const selectedTemplate = this.value;
+    const previewDiv = document.getElementById('templatePreview');
+    const templateImage = document.getElementById('templateImage');
+    const templateTitle = document.getElementById('templateTitle');
+    const templateDescription = document.getElementById('templateDescription');
+
+    if (selectedTemplate) {
+        // Données des modèles
+        const templates = {
+            desert: {
+                title: 'Paysage désertique',
+                description: 'Terrain sablonneux avec dunes et oasis occasionnelles',
+                emoji: '🏜️'
+            },
+            coastal: {
+                title: 'Paysage littoral',
+                description: 'Côtes avec plages, falaises et éléments marins',
+                emoji: '🏖️'
+            },
+            mountain: {
+                title: 'Paysage de montagne',
+                description: 'Reliefs escarpés avec sommets enneigés et vallées',
+                emoji: '🏔️'
+            },
+            rural: {
+                title: 'Paysage rural',
+                description: 'Champs, forêts et éléments agricoles traditionnels',
+                emoji: '🌾'
+            },
+            urban: {
+                title: 'Paysage urbain',
+                description: 'Villes avec bâtiments, routes et infrastructures modernes',
+                emoji: '🏙️'
+            }
+        };
+
+        const template = templates[selectedTemplate];
+        templateImage.innerHTML = `<span style="font-size: 3rem;">${template.emoji}</span>`;
+        templateTitle.textContent = template.title;
+        templateDescription.textContent = template.description;
+        previewDiv.style.display = 'block';
+    } else {
+        previewDiv.style.display = 'none';
+    }
+});
+
+// Validation du formulaire
+document.getElementById('newProjectForm').addEventListener('submit', function(e) {
+    const name = document.getElementById('mapName').value.trim();
+    const width = parseInt(document.getElementById('mapWidth').value);
+    const height = parseInt(document.getElementById('mapHeight').value);
+
+    if (!name) {
+        alert('Veuillez saisir un nom pour votre carte.');
+        e.preventDefault();
+        return;
+    }
+
+    if (width < 100 || width > 2000 || height < 100 || height > 2000) {
+        alert('Les dimensions doivent être comprises entre 100x100 et 2000x2000 pixels.');
+        e.preventDefault();
+        return;
+    }
+
+    // Ici vous pouvez ajouter la logique de création du projet
+    console.log('Création du projet:', { name, width, height, template: document.getElementById('mapTemplate').value });
+});
+</script>
+
+<?php
+include __DIR__ . '/../partials/footer.php';
+?>

+ 3 - 0
logs/app.log

@@ -1,2 +1,5 @@
 [2025-10-11 20:18:41] [EXCEPTION] Exception : Class "HomeController" not found
 [2025-10-11 20:18:43] [EXCEPTION] Exception : Class "HomeController" not found
+[2025-10-11 22:43:24] [EXCEPTION] Exception : Call to undefined function __()
+[2025-10-11 22:44:20] [EXCEPTION] Exception : Call to undefined function __()
+[2025-10-11 22:44:21] [EXCEPTION] Exception : Call to undefined function __()

+ 6 - 0
public/.htaccess

@@ -0,0 +1,6 @@
+RewriteEngine On
+
+# Rediriger toutes les requêtes vers index.php sauf les fichiers existants
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule ^ index.php [QSA,L]

+ 15 - 1
public/index.php

@@ -13,7 +13,19 @@ $config = require_once __DIR__ . '/../config/config.php';
 $routes = require_once __DIR__ . '/../routes/web.php';
 
 // Récupération de l'URI demandée
-$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
+$rawUri = $_SERVER['REQUEST_URI'] ?? '/';
+$uri = parse_url($rawUri, PHP_URL_PATH);
+
+// Gestion des environnements avec un sous-dossier (comme MAMP)
+$basePath = '/map-generator';
+if (strpos($uri, $basePath) === 0) {
+    $uri = substr($uri, strlen($basePath));
+}
+
+// Si l'URI est vide, on la définit sur /
+if (empty($uri)) {
+    $uri = '/';
+}
 
 // Gestion du routing
 if (isset($routes[$uri])) {
@@ -26,6 +38,8 @@ if (isset($routes[$uri])) {
     if (is_array($route) && count($route) === 2) {
         [$controller, $method] = $route;
         $controller::$method();
+    } else {
+        AppDebugger::displayIfDebug('Route mal configurée pour: ' . $uri, 'Router');
     }
 } else {
     // Page 404

+ 2 - 0
routes/web.php

@@ -6,4 +6,6 @@ return [
         AppDebugger::displayIfDebug('Appel de la route /', 'Route');
         return [HomeController::class, 'index'];
     },
+
+    '/projects/new' => [HomeController::class, 'newProject'],
 ];