Spaces:
Build error
Build error
Upload 17 files
Browse files- templates/a_propos.html +235 -0
- templates/checkout.html +278 -0
- templates/conditions_utilisation.html +357 -0
- templates/connexion.html +203 -0
- templates/create_project.html +860 -0
- templates/dashboard.html +466 -0
- templates/documentation.html +285 -0
- templates/index.html +992 -0
- templates/inscription.html +247 -0
- templates/mentions_legales.html +327 -0
- templates/mot_de_passe_oublie.html +238 -0
- templates/nouveau_project.html +376 -0
- templates/politique_confidentialite.html +370 -0
- templates/profile.html +338 -0
- templates/statut.html +468 -0
- templates/support.html +303 -0
- templates/tarifs.html +428 -0
templates/a_propos.html
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>À Propos de Nexus</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet"
|
| 9 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 10 |
+
<style>
|
| 11 |
+
body {
|
| 12 |
+
font-family: 'Inter', sans-serif;
|
| 13 |
+
/* Transition pour un effet doux lors du changement de thème */
|
| 14 |
+
transition: background-color 0.3s, color 0.3s;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Styles pour la barre de navigation fixe */
|
| 18 |
+
.fixed-header {
|
| 19 |
+
position: fixed;
|
| 20 |
+
top: 0;
|
| 21 |
+
left: 0;
|
| 22 |
+
right: 0;
|
| 23 |
+
z-index: 50; /* Pour s'assurer qu'il est au-dessus du contenu */
|
| 24 |
+
/* Tailwind classes already applied: bg-gray-900, border-b border-blue-500/50, py-4 */
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/* Étape 2 : Définir les Styles pour le Mode Clair */
|
| 28 |
+
/* Surcharge des classes Tailwind spécifiques pour simuler le mode clair */
|
| 29 |
+
html.light .bg-gray-900 { background-color: #F3F4F6 !important; /* gray-100 */ }
|
| 30 |
+
html.light .text-white { color: #1F2937 !important; /* gray-900 */ }
|
| 31 |
+
html.light .text-gray-300 { color: #4B5563 !important; /* gray-600 */ }
|
| 32 |
+
html.light .bg-gray-800\/50 { background-color: rgba(209, 213, 219, 0.5) !important; /* gray-300/50 */ }
|
| 33 |
+
html.light .bg-gray-800 { background-color: #E5E7EB !important; /* gray-200 */ }
|
| 34 |
+
html.light .border-gray-700 { border-color: #D1D5DB !important; /* gray-300 */ }
|
| 35 |
+
html.light .text-gray-400 { color: #6B7280 !important; /* gray-500 */ }
|
| 36 |
+
html.light .border-gray-800 { border-color: #D1D5DB !important; /* gray-300 */ }
|
| 37 |
+
html.light .shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
|
| 38 |
+
|
| 39 |
+
/* Style du bouton theme-switch (comme dans le plan) */
|
| 40 |
+
.theme-switch {
|
| 41 |
+
background: none;
|
| 42 |
+
border: none;
|
| 43 |
+
cursor: pointer;
|
| 44 |
+
color: inherit; /* Utilise la couleur du texte parent (text-white ou text-gray-900 en light mode) */
|
| 45 |
+
font-size: 24px;
|
| 46 |
+
padding: 0;
|
| 47 |
+
line-height: 1;
|
| 48 |
+
}
|
| 49 |
+
.theme-switch:hover {
|
| 50 |
+
color: #60A5FA; /* blue-400 */
|
| 51 |
+
}
|
| 52 |
+
</style>
|
| 53 |
+
</head>
|
| 54 |
+
<body class="bg-gray-900 text-white min-h-screen">
|
| 55 |
+
|
| 56 |
+
<div class="relative min-h-screen">
|
| 57 |
+
|
| 58 |
+
<header class="fixed-header w-full bg-gray-900 border-b border-blue-500/50">
|
| 59 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 flex flex-col sm:flex-row justify-between items-center">
|
| 60 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 61 |
+
NEXUS
|
| 62 |
+
</a>
|
| 63 |
+
<nav class="flex items-center space-x-4">
|
| 64 |
+
<a href="/documentation" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 65 |
+
Documentation
|
| 66 |
+
</a>
|
| 67 |
+
<a href="/tarifs" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 68 |
+
Tarifs
|
| 69 |
+
</a>
|
| 70 |
+
|
| 71 |
+
<button id="theme-toggle" class="theme-switch ml-4" aria-label="Basculer le thème">
|
| 72 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 73 |
+
</button>
|
| 74 |
+
|
| 75 |
+
{% if is_logged_in %}
|
| 76 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 rounded-lg hover:bg-blue-700 font-medium transition duration-200">
|
| 77 |
+
Dashboard
|
| 78 |
+
</a>
|
| 79 |
+
{% else %}
|
| 80 |
+
<a href="/connexion" class="px-4 py-2 bg-blue-600 rounded-lg hover:bg-blue-700 font-medium transition duration-200">
|
| 81 |
+
Connexion
|
| 82 |
+
</a>
|
| 83 |
+
{% endif %}
|
| 84 |
+
</nav>
|
| 85 |
+
</div>
|
| 86 |
+
</header>
|
| 87 |
+
|
| 88 |
+
<main class="space-y-12 max-w-4xl mx-auto pt-24 pb-16 px-4 sm:px-6 lg:px-8">
|
| 89 |
+
|
| 90 |
+
<section class="text-center p-8 bg-gray-800/50 rounded-xl shadow-lg">
|
| 91 |
+
<h1 class="text-5xl font-extrabold text-white mb-4 leading-tight">
|
| 92 |
+
Nexus : Notre Mission
|
| 93 |
+
</h1>
|
| 94 |
+
<p class="text-xl text-gray-300 max-w-3xl mx-auto">
|
| 95 |
+
Simplifier la gestion utilisateur pour permettre aux développeurs de se concentrer sur l'innovation.
|
| 96 |
+
</p>
|
| 97 |
+
</section>
|
| 98 |
+
|
| 99 |
+
<section class="space-y-6">
|
| 100 |
+
<h2 class="text-3xl font-bold text-blue-500 border-b border-gray-700 pb-2">
|
| 101 |
+
Qui Sommes-Nous ?
|
| 102 |
+
</h2>
|
| 103 |
+
<p class="text-gray-300">
|
| 104 |
+
Fondée en 2024, Nexus est née de la conviction que l'authentification avancée ne devrait pas être un obstacle pour le développement. Notre plateforme est conçue pour être la couche de gestion d'utilisateur la plus simple et la plus robuste pour toute application web, mobile ou professionnelle.
|
| 105 |
+
</p>
|
| 106 |
+
<p class="text-gray-300 font-medium">
|
| 107 |
+
Nous fournissons une API unique et une URL d'endpoint pour que vous n'ayez aucune configuration complexe à gérer. La sécurité et l'évolutivité sont intégrées.
|
| 108 |
+
</p>
|
| 109 |
+
</section>
|
| 110 |
+
|
| 111 |
+
<section class="space-y-6">
|
| 112 |
+
<h2 class="text-3xl font-bold text-blue-500 border-b border-gray-700 pb-2">
|
| 113 |
+
Notre Vision de l'Avenir
|
| 114 |
+
</h2>
|
| 115 |
+
<div class="grid md:grid-cols-2 gap-6">
|
| 116 |
+
<div class="bg-gray-800 p-6 rounded-xl border-t-4 border-yellow-500">
|
| 117 |
+
<h3 class="text-xl font-semibold text-yellow-400 mb-2">Innovation Continue</h3>
|
| 118 |
+
<p class="text-gray-300">Intégrer l'IA pour l'analyse des logs et le support prédictif pour les développeurs.</p>
|
| 119 |
+
</div>
|
| 120 |
+
<div class="bg-gray-800 p-6 rounded-xl border-t-4 border-purple-500">
|
| 121 |
+
<h3 class="text-xl font-semibold text-purple-400 mb-2">Sécurité Unifiée</h3>
|
| 122 |
+
<p class="text-gray-300">Établir la norme en matière de cybersécurité pour les petits et grands comptes utilisateurs.</p>
|
| 123 |
+
</div>
|
| 124 |
+
</div>
|
| 125 |
+
</section>
|
| 126 |
+
|
| 127 |
+
<section class="text-center pt-8">
|
| 128 |
+
<h2 class="text-3xl font-bold text-white mb-4">Prêt à nous rejoindre ?</h2>
|
| 129 |
+
<a href="/inscription" class="px-6 py-3 bg-blue-600 text-white text-lg font-bold rounded-xl shadow-md hover:bg-blue-700 transition duration-300">
|
| 130 |
+
Créer un Compte Gratuit
|
| 131 |
+
</a>
|
| 132 |
+
</section>
|
| 133 |
+
|
| 134 |
+
</main>
|
| 135 |
+
|
| 136 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900">
|
| 137 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 138 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 139 |
+
|
| 140 |
+
<div class="col-span-2 lg:col-span-1">
|
| 141 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 142 |
+
<p class="mt-3 text-gray-400">
|
| 143 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 144 |
+
</p>
|
| 145 |
+
<div class="mt-4 flex space-x-4">
|
| 146 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 147 |
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.014 4.85.07c3.275.146 4.47 1.583 4.61 4.85.056 1.266.07 1.646.07 4.85s-.014 3.584-.07 4.85c-.14 3.267-1.335 4.704-4.61 4.85-1.266.056-1.646.07-4.85.07s-3.584-.014-4.85-.07c-3.275-.146-4.47-1.583-4.61-4.85-.056-1.266-.07-1.646-.07-4.85s.014-3.584.07-4.85c.14-3.267 1.335-4.704 4.61-4.85 1.266-.056 1.646-.07 4.85-.07zM12 0c-3.784 0-4.285.016-5.773.083-4.722.211-6.755 2.24-6.965 6.965C.016 7.715 0 8.216 0 12s.016 4.285.083 5.773c.21 4.721 2.239 6.755 6.965 6.965 1.488.067 1.99.083 5.773.083s4.285-.016 5.773-.083c4.721-.21 6.755-2.239 6.965-6.965.067-1.488.083-1.99.083-5.773s-.016-4.285-.083-5.773c-.21-4.722-2.239-6.755-6.965-6.965C16.285.016 15.784 0 12 0zm0 14.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z"/></svg>
|
| 148 |
+
</a>
|
| 149 |
+
</div>
|
| 150 |
+
</div>
|
| 151 |
+
|
| 152 |
+
<div>
|
| 153 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 154 |
+
<ul class="space-y-3 text-gray-400">
|
| 155 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 156 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 157 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 158 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 159 |
+
</ul>
|
| 160 |
+
</div>
|
| 161 |
+
|
| 162 |
+
<div>
|
| 163 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 164 |
+
<ul class="space-y-3 text-gray-400">
|
| 165 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 166 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 167 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 168 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 169 |
+
</ul>
|
| 170 |
+
</div>
|
| 171 |
+
|
| 172 |
+
<div class="col-span-2 md:col-span-1">
|
| 173 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 174 |
+
<ul class="space-y-3 text-gray-400">
|
| 175 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 176 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 177 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 178 |
+
</ul>
|
| 179 |
+
</div>
|
| 180 |
+
|
| 181 |
+
</div>
|
| 182 |
+
|
| 183 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm">
|
| 184 |
+
© 2024 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 185 |
+
</div>
|
| 186 |
+
</div>
|
| 187 |
+
</footer>
|
| 188 |
+
|
| 189 |
+
</div>
|
| 190 |
+
|
| 191 |
+
<script>
|
| 192 |
+
// Logique de bascule du mode sombre/clair
|
| 193 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 194 |
+
const htmlElement = document.documentElement;
|
| 195 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 196 |
+
|
| 197 |
+
// Charger le thème depuis le localStorage
|
| 198 |
+
const savedTheme = localStorage.getItem('theme');
|
| 199 |
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
| 200 |
+
|
| 201 |
+
// Déterminer le thème initial
|
| 202 |
+
let initialTheme = 'dark';
|
| 203 |
+
if (savedTheme) {
|
| 204 |
+
initialTheme = savedTheme;
|
| 205 |
+
} else if (!prefersDark) {
|
| 206 |
+
// Si pas de localStorage, utiliser le thème du système (par défaut sombre ici, sauf si système clair)
|
| 207 |
+
initialTheme = 'light';
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
// Appliquer le thème initial
|
| 211 |
+
if (initialTheme === 'light') {
|
| 212 |
+
htmlElement.classList.add('light');
|
| 213 |
+
iconElement.textContent = 'dark_mode';
|
| 214 |
+
} else {
|
| 215 |
+
// Thème sombre (par défaut)
|
| 216 |
+
iconElement.textContent = 'light_mode';
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
themeToggle.addEventListener('click', () => {
|
| 221 |
+
if (htmlElement.classList.contains('light')) {
|
| 222 |
+
// Passage de Clair à Sombre
|
| 223 |
+
htmlElement.classList.remove('light');
|
| 224 |
+
localStorage.setItem('theme', 'dark');
|
| 225 |
+
iconElement.textContent = 'light_mode';
|
| 226 |
+
} else {
|
| 227 |
+
// Passage de Sombre à Clair
|
| 228 |
+
htmlElement.classList.add('light');
|
| 229 |
+
localStorage.setItem('theme', 'light');
|
| 230 |
+
iconElement.textContent = 'dark_mode';
|
| 231 |
+
}
|
| 232 |
+
});
|
| 233 |
+
</script>
|
| 234 |
+
</body>
|
| 235 |
+
</html>
|
templates/checkout.html
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 7 |
+
<title>Paiement - Nexus Pro</title>
|
| 8 |
+
<link rel="stylesheet"
|
| 9 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 10 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 11 |
+
<script src="https://js.stripe.com/v3/"></script>
|
| 12 |
+
<style>
|
| 13 |
+
/* Variables de Thème - Couleurs Noir Foncé (Mode Sombre par défaut) */
|
| 14 |
+
:root, html.dark {
|
| 15 |
+
--bg-page: #181818; /* Noir très foncé, pas de bleu marine */
|
| 16 |
+
--bg-card: #282828;
|
| 17 |
+
--text-main: #EAEAEA;
|
| 18 |
+
--text-secondary: #B0B0B0;
|
| 19 |
+
--border-color: #404040;
|
| 20 |
+
--shadow-color: rgba(0, 0, 0, 0.5);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
/* Mode Clair */
|
| 24 |
+
html.light {
|
| 25 |
+
--bg-page: #F5F5F5;
|
| 26 |
+
--bg-card: #FFFFFF;
|
| 27 |
+
--text-main: #202020;
|
| 28 |
+
--text-secondary: #5C5C5C;
|
| 29 |
+
--border-color: #E0E0E0;
|
| 30 |
+
--shadow-color: rgba(0, 0, 0, 0.1);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
/* Application des variables */
|
| 34 |
+
body {
|
| 35 |
+
background-color: var(--bg-page);
|
| 36 |
+
color: var(--text-main);
|
| 37 |
+
transition: background-color 0.3s, color 0.3s;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.bg-gray-900 { background-color: var(--bg-page) !important; }
|
| 41 |
+
.text-white { color: var(--text-main) !important; }
|
| 42 |
+
.bg-gray-800, .bg-gray-800\/50 {
|
| 43 |
+
background-color: var(--bg-card) !important;
|
| 44 |
+
box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -2px var(--shadow-color);
|
| 45 |
+
}
|
| 46 |
+
.text-gray-400 { color: var(--text-secondary) !important; }
|
| 47 |
+
.border-gray-700, .border-gray-800 { border-color: var(--border-color) !important; }
|
| 48 |
+
.text-gray-300 { color: var(--text-secondary) !important; } /* Utilisation de la même couleur pour uniformité */
|
| 49 |
+
.bg-gray-700 { background-color: #404040 !important; }
|
| 50 |
+
.theme-switch {
|
| 51 |
+
background: none;
|
| 52 |
+
border: none;
|
| 53 |
+
cursor: pointer;
|
| 54 |
+
color: var(--text-main);
|
| 55 |
+
font-size: 24px;
|
| 56 |
+
transition: color 0.2s;
|
| 57 |
+
padding: 0.5rem; /* Espace autour du bouton */
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
/* Style pour l'élément Stripe Elements (input) */
|
| 61 |
+
#card-element {
|
| 62 |
+
padding: 1rem;
|
| 63 |
+
border: 1px solid var(--border-color);
|
| 64 |
+
background-color: var(--bg-card);
|
| 65 |
+
border-radius: 0.5rem;
|
| 66 |
+
margin-bottom: 1rem;
|
| 67 |
+
color: var(--text-main); /* Assurez-vous que le texte par défaut est lisible */
|
| 68 |
+
}
|
| 69 |
+
</style>
|
| 70 |
+
</head>
|
| 71 |
+
<body class="min-h-screen">
|
| 72 |
+
|
| 73 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 74 |
+
|
| 75 |
+
<header class="sticky top-0 z-50 flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8 bg-gray-900" style="background-color: var(--bg-page); transition: background-color 0.3s;">
|
| 76 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 77 |
+
NEXUS
|
| 78 |
+
</a>
|
| 79 |
+
<nav class="flex items-center space-x-4">
|
| 80 |
+
<a href="/documentation" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 81 |
+
Documentation
|
| 82 |
+
</a>
|
| 83 |
+
<a href="/a-propos" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 84 |
+
À Propos
|
| 85 |
+
</a>
|
| 86 |
+
|
| 87 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 88 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 89 |
+
</button>
|
| 90 |
+
|
| 91 |
+
{% if is_logged_in %}
|
| 92 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 border border-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 93 |
+
Dashboard
|
| 94 |
+
</a>
|
| 95 |
+
{% else %}
|
| 96 |
+
<a href="/connexion" class="px-4 py-2 bg-blue-600 border border-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 97 |
+
Connexion
|
| 98 |
+
</a>
|
| 99 |
+
{% endif %}
|
| 100 |
+
</nav>
|
| 101 |
+
</header>
|
| 102 |
+
|
| 103 |
+
<main class="flex flex-col items-center">
|
| 104 |
+
|
| 105 |
+
<div class="max-w-xl w-full p-6 sm:p-8 bg-gray-800 shadow-2xl border-t-4 border-blue-500">
|
| 106 |
+
|
| 107 |
+
<h1 class="text-3xl font-extrabold text-white mb-6 text-center">
|
| 108 |
+
Finaliser votre Commande
|
| 109 |
+
</h1>
|
| 110 |
+
|
| 111 |
+
<div class="mb-8 border border-gray-700 p-4">
|
| 112 |
+
<h2 class="text-xl font-bold text-white mb-3 border-b border-gray-700 pb-2">
|
| 113 |
+
Récapitulatif
|
| 114 |
+
</h2>
|
| 115 |
+
|
| 116 |
+
<div class="space-y-2 text-gray-300">
|
| 117 |
+
<div class="flex justify-between">
|
| 118 |
+
<span>Plan Sélectionné:</span>
|
| 119 |
+
<span class="font-semibold text-white">{{ plan.title }}</span>
|
| 120 |
+
</div>
|
| 121 |
+
<div class="text-sm italic text-gray-400">
|
| 122 |
+
{{ plan.description }}
|
| 123 |
+
</div>
|
| 124 |
+
<div class="flex justify-between pt-2 border-t border-gray-700 font-bold text-lg text-yellow-400">
|
| 125 |
+
<span>Total (TVA incluse):</span>
|
| 126 |
+
<span>{{ plan.price_display }}</span>
|
| 127 |
+
</div>
|
| 128 |
+
</div>
|
| 129 |
+
</div>
|
| 130 |
+
|
| 131 |
+
<form id="payment-form">
|
| 132 |
+
<h2 class="text-xl font-bold text-white mb-4">
|
| 133 |
+
Informations de Paiement
|
| 134 |
+
</h2>
|
| 135 |
+
|
| 136 |
+
<div id="card-element" class="shadow-md">
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<div id="card-errors" role="alert" class="text-red-500 text-sm mb-4"></div>
|
| 140 |
+
|
| 141 |
+
<button id="submit-button" class="w-full px-6 py-3 bg-blue-600 text-white text-lg font-bold shadow-md hover:bg-blue-700 transition duration-300" type="submit">
|
| 142 |
+
Payer maintenant {{ plan.price_display }}
|
| 143 |
+
</button>
|
| 144 |
+
</form>
|
| 145 |
+
|
| 146 |
+
</div>
|
| 147 |
+
|
| 148 |
+
</main>
|
| 149 |
+
|
| 150 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 151 |
+
© 2025 Nexus. Paiement Sécurisé par Stripe.
|
| 152 |
+
</footer>
|
| 153 |
+
</div>
|
| 154 |
+
|
| 155 |
+
<script>
|
| 156 |
+
// Logique de bascule du mode sombre/clair (à inclure pour l'uniformité)
|
| 157 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 158 |
+
const htmlElement = document.documentElement;
|
| 159 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 160 |
+
const savedTheme = localStorage.getItem('theme');
|
| 161 |
+
if (savedTheme === 'light') {
|
| 162 |
+
htmlElement.classList.remove('dark');
|
| 163 |
+
htmlElement.classList.add('light');
|
| 164 |
+
iconElement.textContent = 'dark_mode';
|
| 165 |
+
} else {
|
| 166 |
+
htmlElement.classList.add('dark');
|
| 167 |
+
htmlElement.classList.remove('light');
|
| 168 |
+
iconElement.textContent = 'light_mode';
|
| 169 |
+
}
|
| 170 |
+
themeToggle.addEventListener('click', () => {
|
| 171 |
+
if (htmlElement.classList.contains('light')) {
|
| 172 |
+
htmlElement.classList.remove('light');
|
| 173 |
+
htmlElement.classList.add('dark');
|
| 174 |
+
localStorage.setItem('theme', 'dark');
|
| 175 |
+
iconElement.textContent = 'light_mode';
|
| 176 |
+
} else {
|
| 177 |
+
htmlElement.classList.add('light');
|
| 178 |
+
htmlElement.classList.remove('dark');
|
| 179 |
+
localStorage.setItem('theme', 'light');
|
| 180 |
+
iconElement.textContent = 'dark_mode';
|
| 181 |
+
}
|
| 182 |
+
});
|
| 183 |
+
|
| 184 |
+
// =======================================================
|
| 185 |
+
// LOGIQUE D'INTÉGRATION STRIPE ELEMENTS
|
| 186 |
+
// =======================================================
|
| 187 |
+
const planId = new URLSearchParams(window.location.search).get('plan');
|
| 188 |
+
const stripe = Stripe("{{ stripe_public_key }}"); // Clé publique injectée par Jinja
|
| 189 |
+
const elements = stripe.elements();
|
| 190 |
+
const cardElement = elements.create('card', {
|
| 191 |
+
style: {
|
| 192 |
+
base: {
|
| 193 |
+
color: htmlElement.classList.contains('light') ? '#202020' : '#EAEAEA',
|
| 194 |
+
fontFamily: 'system-ui, sans-serif',
|
| 195 |
+
fontSmoothing: 'antialiased',
|
| 196 |
+
fontSize: '16px',
|
| 197 |
+
'::placeholder': {
|
| 198 |
+
color: htmlElement.classList.contains('light') ? '#5C5C5C' : '#B0B0B0',
|
| 199 |
+
},
|
| 200 |
+
},
|
| 201 |
+
invalid: {
|
| 202 |
+
color: '#EF4444',
|
| 203 |
+
iconColor: '#EF4444',
|
| 204 |
+
},
|
| 205 |
+
}
|
| 206 |
+
});
|
| 207 |
+
|
| 208 |
+
cardElement.mount('#card-element');
|
| 209 |
+
|
| 210 |
+
const form = document.getElementById('payment-form');
|
| 211 |
+
const submitButton = document.getElementById('submit-button');
|
| 212 |
+
const cardErrors = document.getElementById('card-errors');
|
| 213 |
+
let clientSecret = null; // Pour stocker le Client Secret reçu du backend
|
| 214 |
+
|
| 215 |
+
// 1. Récupérer le Client Secret du backend au chargement de la page
|
| 216 |
+
async function fetchClientSecret() {
|
| 217 |
+
try {
|
| 218 |
+
// Requête au backend pour créer le PaymentIntent
|
| 219 |
+
const response = await fetch('/api/create-payment-intent', {
|
| 220 |
+
method: 'POST',
|
| 221 |
+
headers: {
|
| 222 |
+
'Content-Type': 'application/json'
|
| 223 |
+
},
|
| 224 |
+
body: JSON.stringify({ plan_id: planId })
|
| 225 |
+
});
|
| 226 |
+
|
| 227 |
+
if (!response.ok) {
|
| 228 |
+
throw new Error('Erreur lors de la création du PaymentIntent.');
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
const data = await response.json();
|
| 232 |
+
clientSecret = data.client_secret;
|
| 233 |
+
|
| 234 |
+
} catch (error) {
|
| 235 |
+
console.error('Erreur Stripe:', error);
|
| 236 |
+
cardErrors.textContent = "Erreur: Impossible d'initialiser le paiement. Veuillez réessayer.";
|
| 237 |
+
submitButton.disabled = true;
|
| 238 |
+
}
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
// 2. Traiter la soumission du formulaire
|
| 242 |
+
form.addEventListener('submit', async (event) => {
|
| 243 |
+
event.preventDefault();
|
| 244 |
+
|
| 245 |
+
if (!clientSecret) {
|
| 246 |
+
cardErrors.textContent = "Veuillez patienter pendant l'initialisation du paiement.";
|
| 247 |
+
return;
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
submitButton.disabled = true;
|
| 251 |
+
submitButton.textContent = 'Traitement en cours...';
|
| 252 |
+
|
| 253 |
+
// Confirmer le paiement côté client avec le clientSecret et l'élément Stripe
|
| 254 |
+
const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
|
| 255 |
+
payment_method: {
|
| 256 |
+
card: cardElement,
|
| 257 |
+
billing_details: {
|
| 258 |
+
// Idéalement, les détails de l'utilisateur (email/nom) devraient être fournis ici
|
| 259 |
+
},
|
| 260 |
+
}
|
| 261 |
+
});
|
| 262 |
+
|
| 263 |
+
if (error) {
|
| 264 |
+
// Afficher les erreurs (ex: carte refusée, données invalides)
|
| 265 |
+
cardErrors.textContent = error.message;
|
| 266 |
+
submitButton.disabled = false;
|
| 267 |
+
submitButton.textContent = 'Payer maintenant {{ plan.price_display }}';
|
| 268 |
+
} else if (paymentIntent.status === 'succeeded') {
|
| 269 |
+
// Le paiement a réussi
|
| 270 |
+
window.location.href = `/dashboard?payment=success&intent=${paymentIntent.id}`;
|
| 271 |
+
}
|
| 272 |
+
});
|
| 273 |
+
|
| 274 |
+
// Démarrage : Récupérer le client secret au chargement
|
| 275 |
+
fetchClientSecret();
|
| 276 |
+
</script>
|
| 277 |
+
</body>
|
| 278 |
+
</html>
|
templates/conditions_utilisation.html
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Conditions d'Utilisation - Nexus</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.21.0/tocbot.css">
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
body { font-family: 'Inter', sans-serif; }
|
| 13 |
+
/* Style pour les boutons carrés */
|
| 14 |
+
.btn-square {
|
| 15 |
+
border-radius: 0;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
/* Définition du thème via classes */
|
| 19 |
+
/* Mode Sombre (par défaut, pour .dark sur html) */
|
| 20 |
+
.dark {
|
| 21 |
+
--bg-body: #0a0a0a; /* Noir très foncé */
|
| 22 |
+
--bg-main: #0a0a0a;
|
| 23 |
+
--text-color: #E3E3E3;
|
| 24 |
+
--border-color: #3B82F64D; /* blue-500/50 */
|
| 25 |
+
--toc-bg: #111827; /* gray-900 */
|
| 26 |
+
--toc-border: #374151; /* gray-700 */
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Mode Clair (pour html sans .dark) */
|
| 30 |
+
html:not(.dark) {
|
| 31 |
+
--bg-body: #ffffff;
|
| 32 |
+
--bg-main: #ffffff;
|
| 33 |
+
--text-color: #1F2937; /* gray-800 */
|
| 34 |
+
--border-color: #3B82F6; /* blue-500 */
|
| 35 |
+
--toc-bg: #F9FAFB; /* gray-50 */
|
| 36 |
+
--toc-border: #E5E7EB; /* gray-200 */
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
/* Application des variables aux éléments de base */
|
| 40 |
+
.dark body, html:not(.dark) body {
|
| 41 |
+
background-color: var(--bg-body);
|
| 42 |
+
color: var(--text-color);
|
| 43 |
+
transition: background-color 0.3s, color 0.3s;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
/* Styles personnalisés pour intégrer Tocbot au thème */
|
| 47 |
+
.toc-list {
|
| 48 |
+
list-style: none;
|
| 49 |
+
padding-left: 0;
|
| 50 |
+
margin: 0;
|
| 51 |
+
}
|
| 52 |
+
.toc-list-item {
|
| 53 |
+
margin-bottom: 0.25rem;
|
| 54 |
+
}
|
| 55 |
+
.toc-list-item a {
|
| 56 |
+
display: block;
|
| 57 |
+
padding: 0.5rem 0.75rem;
|
| 58 |
+
color: var(--text-color);
|
| 59 |
+
border-left: 2px solid transparent;
|
| 60 |
+
transition: all 0.2s;
|
| 61 |
+
font-size: 0.9rem;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
.dark .toc-list-item a { color: #9CA3AF; } /* gray-400 */
|
| 65 |
+
html:not(.dark) .toc-list-item a { color: #4B5563; } /* gray-600 */
|
| 66 |
+
|
| 67 |
+
.dark .toc-list-item a:hover {
|
| 68 |
+
color: #fff;
|
| 69 |
+
border-left-color: #3B82F6;
|
| 70 |
+
}
|
| 71 |
+
html:not(.dark) .toc-list-item a:hover {
|
| 72 |
+
color: #1F2937;
|
| 73 |
+
border-left-color: #3B82F6;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.is-active-link {
|
| 77 |
+
font-weight: 700;
|
| 78 |
+
color: #3B82F6 !important; /* blue-500 */
|
| 79 |
+
border-left-color: #3B82F6 !important;
|
| 80 |
+
background-color: #1F2937; /* gray-800 */
|
| 81 |
+
border-radius: 0;
|
| 82 |
+
}
|
| 83 |
+
html:not(.dark) .is-active-link {
|
| 84 |
+
background-color: #E5E7EB; /* gray-200 */
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
/* Style du bouton theme-switch (Etape 2: Style du bouton) */
|
| 88 |
+
.theme-switch {
|
| 89 |
+
background: none;
|
| 90 |
+
border: none;
|
| 91 |
+
cursor: pointer;
|
| 92 |
+
color: var(--text-color);
|
| 93 |
+
font-size: 24px;
|
| 94 |
+
transition: color 0.2s;
|
| 95 |
+
padding: 0.5rem;
|
| 96 |
+
}
|
| 97 |
+
.theme-switch:hover {
|
| 98 |
+
color: #3B82F6; /* blue-500 */
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
/* Rendre le conteneur TOC moins large verticalement sur les grands écrans */
|
| 102 |
+
@media (min-width: 1024px) {
|
| 103 |
+
.js-toc-container {
|
| 104 |
+
max-height: calc(100vh - 8rem); /* Ajuste la hauteur pour qu'il ne prenne pas toute la hauteur de l'écran */
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
@media (max-width: 1023px) {
|
| 109 |
+
.js-toc-container { display: none; }
|
| 110 |
+
}
|
| 111 |
+
</style>
|
| 112 |
+
<script>
|
| 113 |
+
tailwind.config = {
|
| 114 |
+
darkMode: 'class',
|
| 115 |
+
theme: {
|
| 116 |
+
extend: {
|
| 117 |
+
colors: {
|
| 118 |
+
'gray-950': '#0a0a0a', // Noir très foncé pour le mode sombre
|
| 119 |
+
}
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
</script>
|
| 124 |
+
</head>
|
| 125 |
+
<body class="bg-gray-950 text-white min-h-screen transition-colors duration-300">
|
| 126 |
+
|
| 127 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 128 |
+
|
| 129 |
+
<header class="sticky top-0 z-50 flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8 bg-gray-950 dark:bg-gray-950 transition-colors duration-300">
|
| 130 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 131 |
+
NEXUS
|
| 132 |
+
</a>
|
| 133 |
+
<nav class="flex items-center space-x-4">
|
| 134 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 135 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 136 |
+
</button>
|
| 137 |
+
<a href="/connexion" class="px-6 py-3 bg-blue-600 text-white font-bold hover:bg-blue-700 transition duration-300 btn-square shadow-md">
|
| 138 |
+
Se Connecter
|
| 139 |
+
</a>
|
| 140 |
+
</nav>
|
| 141 |
+
</header>
|
| 142 |
+
|
| 143 |
+
<main class="flex flex-col lg:flex-row lg:space-x-8">
|
| 144 |
+
|
| 145 |
+
<div class="lg:w-3/4 js-toc-content">
|
| 146 |
+
|
| 147 |
+
<h1 class="text-4xl font-extrabold text-gray-900 dark:text-white mb-6">
|
| 148 |
+
Conditions Générales d'Utilisation (CGU)
|
| 149 |
+
</h1>
|
| 150 |
+
<p class="text-gray-600 dark:text-gray-400 text-lg mb-10 border-l-4 border-blue-500 pl-4 italic">
|
| 151 |
+
Ces conditions régissent l'accès et l'utilisation de tous les services Nexus. L'utilisation de notre plateforme vaut acceptation.
|
| 152 |
+
</p>
|
| 153 |
+
|
| 154 |
+
<h2 id="acceptation-cgu" class="text-3xl font-bold text-blue-500 dark:text-blue-400 mt-10 mb-4 pt-2">
|
| 155 |
+
1. Acceptation des Conditions
|
| 156 |
+
</h2>
|
| 157 |
+
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
| 158 |
+
En créant un compte, en vous connectant, en accédant à l'API ou en utilisant l'un des services fournis par Nexus, vous reconnaissez avoir lu, compris et accepté d'être lié par les présentes Conditions Générales d'Utilisation (les "CGU"), ainsi que par notre Politique de Confidentialité. Si vous n'acceptez pas ces CGU, vous ne devez pas utiliser la Plateforme.
|
| 159 |
+
</p>
|
| 160 |
+
|
| 161 |
+
<h2 id="services-api" class="text-3xl font-bold text-blue-500 dark:text-blue-400 mt-10 mb-4 pt-2">
|
| 162 |
+
2. Description des Services et de l'API
|
| 163 |
+
</h2>
|
| 164 |
+
<p class="text-gray-700 dark:text-gray-300 mb-4">
|
| 165 |
+
Nexus est une plateforme de services d'infrastructure API (SaaS). L'accès à l'API est fourni par le biais d'une clé API unique et confidentielle associée à votre compte.
|
| 166 |
+
</p>
|
| 167 |
+
|
| 168 |
+
<h3 id="cle-api" class="text-2xl font-semibold text-gray-900 dark:text-white mt-8 mb-3 pt-2">
|
| 169 |
+
2.1. Clé API et Sécurité
|
| 170 |
+
</h3>
|
| 171 |
+
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
| 172 |
+
Vous êtes responsable du maintien de la confidentialité de votre clé API. Toute activité effectuée sous votre clé API sera considérée comme ayant été effectuée par vous. Vous devez nous notifier immédiatement de toute utilisation non autorisée ou de toute autre violation de sécurité.
|
| 173 |
+
</p>
|
| 174 |
+
|
| 175 |
+
<h3 id="limites-utilisation" class="text-2xl font-semibold text-gray-900 dark:text-white mt-8 mb-3 pt-2">
|
| 176 |
+
2.2. Limites d'Utilisation
|
| 177 |
+
</h3>
|
| 178 |
+
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
| 179 |
+
Chaque plan d'abonnement (voir `/tarifs`) est soumis à des limites strictes de requêtes mensuelles ou horaires. Le dépassement de ces limites peut entraîner des frais supplémentaires ou la suspension de l'accès à l'API. Nous nous réservons le droit de modifier les limites à tout moment avec un préavis.
|
| 180 |
+
</p>
|
| 181 |
+
|
| 182 |
+
<h2 id="obligations-utilisateur" class="text-3xl font-bold text-blue-500 dark:text-blue-400 mt-10 mb-4 pt-2">
|
| 183 |
+
3. Obligations de l'Utilisateur
|
| 184 |
+
</h2>
|
| 185 |
+
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4 mb-6">
|
| 186 |
+
<li>Ne pas utiliser l'API à des fins illégales, frauduleuses, ou non autorisées.</li>
|
| 187 |
+
<li>Ne pas tenter de perturber ou de contourner les mesures de sécurité de Nexus (comme le *rate limiting*).</li>
|
| 188 |
+
<li>S'assurer que les données transmises via l'API ne contiennent aucun virus ou code malveillant.</li>
|
| 189 |
+
<li>Ne pas revendre, céder ou transférer votre clé API ou votre compte à un tiers sans notre autorisation écrite.</li>
|
| 190 |
+
</ul>
|
| 191 |
+
|
| 192 |
+
<h2 id="suspension-resiliation" class="text-3xl font-bold text-blue-500 dark:text-blue-400 mt-10 mb-4 pt-2">
|
| 193 |
+
4. Suspension et Résiliation
|
| 194 |
+
</h2>
|
| 195 |
+
<p class="text-gray-700 dark:text-gray-300 mb-4">
|
| 196 |
+
Nexus se réserve le droit de suspendre ou de résilier votre accès aux Services API, sans préavis ni responsabilité, si :
|
| 197 |
+
</p>
|
| 198 |
+
<ul class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4 mb-6">
|
| 199 |
+
<li>Vous enfreignez de manière significative les présentes CGU.</li>
|
| 200 |
+
<li>Vous ne payez pas les frais d'abonnement ou de dépassement à l'échéance.</li>
|
| 201 |
+
<li>Nous avons des motifs raisonnables de croire que votre utilisation compromet la sécurité de la Plateforme ou des autres Utilisateurs.</li>
|
| 202 |
+
</ul>
|
| 203 |
+
|
| 204 |
+
<h2 id="dispositions-financieres" class="text-3xl font-bold text-blue-500 dark:text-blue-400 mt-10 mb-4 pt-2">
|
| 205 |
+
5. Dispositions Financières
|
| 206 |
+
</h2>
|
| 207 |
+
<h3 id="tarification" class="text-2xl font-semibold text-gray-900 dark:text-white mt-8 mb-3 pt-2">
|
| 208 |
+
5.1. Tarification et Facturation
|
| 209 |
+
</h3>
|
| 210 |
+
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
| 211 |
+
Les frais d'accès et les modalités de paiement sont détaillés sur la page `/tarifs`. Les abonnements sont payables d'avance. Tous les frais sont facturés en Euros (€) et sont dus immédiatement.
|
| 212 |
+
</p>
|
| 213 |
+
|
| 214 |
+
<h3 id="remboursement" class="text-2xl font-semibold text-gray-900 dark:text-white mt-8 mb-3 pt-2">
|
| 215 |
+
5.2. Politique de Remboursement
|
| 216 |
+
</h3>
|
| 217 |
+
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
| 218 |
+
Sauf indication contraire explicite pour des promotions spécifiques, tous les frais d'abonnement et de consommation d'API sont non remboursables. La résiliation de votre abonnement ne donne pas droit à un remboursement des périodes non utilisées.
|
| 219 |
+
</p>
|
| 220 |
+
|
| 221 |
+
<h2 id="droit-applicable" class="text-3xl font-bold text-blue-500 dark:text-blue-400 mt-10 mb-4 pt-2">
|
| 222 |
+
6. Droit Applicable et Juridiction
|
| 223 |
+
</h2>
|
| 224 |
+
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
| 225 |
+
Les présentes CGU sont régies et interprétées conformément aux lois de [Pays du Siège Social]. Tout litige relatif à l'interprétation ou à l'exécution de ces CGU sera soumis à la compétence exclusive des tribunaux de [Ville du Siège Social].
|
| 226 |
+
</p>
|
| 227 |
+
|
| 228 |
+
<div class="mt-12 text-center">
|
| 229 |
+
<a href="/tarifs" class="px-6 py-3 bg-teal-600 text-white text-lg font-bold hover:bg-teal-700 transition duration-300 btn-square shadow-xl">
|
| 230 |
+
Consulter les Tarifs
|
| 231 |
+
</a>
|
| 232 |
+
</div>
|
| 233 |
+
|
| 234 |
+
</div>
|
| 235 |
+
|
| 236 |
+
<div class="lg:w-1/4 pt-4 sticky top-24 lg:h-auto js-toc-container">
|
| 237 |
+
<div class="lg:sticky lg:top-[7rem] p-4 border border-gray-700 dark:border-gray-700 bg-gray-100/50 dark:bg-gray-900/50 rounded-lg shadow-lg">
|
| 238 |
+
<h3 class="text-xl font-semibold mb-4 text-blue-500">Navigation Rapide</h3>
|
| 239 |
+
<div class="js-toc"></div>
|
| 240 |
+
</div>
|
| 241 |
+
</div>
|
| 242 |
+
|
| 243 |
+
</main>
|
| 244 |
+
|
| 245 |
+
</div>
|
| 246 |
+
|
| 247 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.21.0/tocbot.min.js"></script>
|
| 248 |
+
<script>
|
| 249 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 250 |
+
tocbot.init({
|
| 251 |
+
tocSelector: '.js-toc',
|
| 252 |
+
contentSelector: '.js-toc-content',
|
| 253 |
+
headingSelector: 'h2, h3',
|
| 254 |
+
hasSmoothScroll: true,
|
| 255 |
+
headingsOffset: 60,
|
| 256 |
+
scrollSmoothOffset: -60,
|
| 257 |
+
});
|
| 258 |
+
});
|
| 259 |
+
</script>
|
| 260 |
+
|
| 261 |
+
<script>
|
| 262 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 263 |
+
const htmlElement = document.documentElement;
|
| 264 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 265 |
+
|
| 266 |
+
// Charger le thème depuis le localStorage
|
| 267 |
+
const savedTheme = localStorage.getItem('theme');
|
| 268 |
+
|
| 269 |
+
// Définir le thème initial
|
| 270 |
+
if (savedTheme === 'light') {
|
| 271 |
+
htmlElement.classList.remove('dark');
|
| 272 |
+
iconElement.textContent = 'dark_mode';
|
| 273 |
+
} else if (savedTheme === 'dark') {
|
| 274 |
+
htmlElement.classList.add('dark');
|
| 275 |
+
iconElement.textContent = 'light_mode';
|
| 276 |
+
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
| 277 |
+
// Si pas de thème sauvegardé, utiliser la préférence système (en conservant la classe 'dark' par défaut)
|
| 278 |
+
htmlElement.classList.add('dark');
|
| 279 |
+
iconElement.textContent = 'light_mode';
|
| 280 |
+
} else {
|
| 281 |
+
htmlElement.classList.remove('dark');
|
| 282 |
+
iconElement.textContent = 'dark_mode';
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
themeToggle.addEventListener('click', () => {
|
| 287 |
+
// Bascule
|
| 288 |
+
if (htmlElement.classList.contains('dark')) {
|
| 289 |
+
// Passage de sombre à clair
|
| 290 |
+
htmlElement.classList.remove('dark');
|
| 291 |
+
localStorage.setItem('theme', 'light');
|
| 292 |
+
iconElement.textContent = 'dark_mode';
|
| 293 |
+
} else {
|
| 294 |
+
// Passage de clair à sombre
|
| 295 |
+
htmlElement.classList.add('dark');
|
| 296 |
+
localStorage.setItem('theme', 'dark');
|
| 297 |
+
iconElement.textContent = 'light_mode';
|
| 298 |
+
}
|
| 299 |
+
});
|
| 300 |
+
</script>
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
<footer class="mt-16 border-t border-gray-700 dark:border-gray-700 bg-gray-50 dark:bg-gray-950 transition-colors duration-300">
|
| 304 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 305 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 306 |
+
|
| 307 |
+
<div class="col-span-2 lg:col-span-1">
|
| 308 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 309 |
+
<p class="mt-3 text-gray-500 dark:text-gray-400">
|
| 310 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 311 |
+
</p>
|
| 312 |
+
<div class="mt-4 flex space-x-4">
|
| 313 |
+
<a href="#" class="text-gray-500 dark:text-gray-400 hover:text-blue-500 transition duration-200">
|
| 314 |
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.014 4.85.07c3.275.146 4.47 1.583 4.61 4.85.056 1.266.07 1.646.07 4.85s-.014 3.584-.07 4.85c-.14 3.267-1.335 4.704-4.61 4.85-1.266.056-1.646.07-4.85.07s-3.584-.014-4.85-.07c-3.275-.146-4.47-1.583-4.61-4.85-.056-1.266-.07-1.646-.07-4.85s.014-3.584.07-4.85c.14-3.267 1.335-4.704 4.61-4.85 1.266-.056 1.646-.07 4.85-.07zM12 0c-3.784 0-4.285.016-5.773.083-4.722.211-6.755 2.24-6.965 6.965C.016 7.715 0 8.216 0 12s.016 4.285.083 5.773c.21 4.721 2.239 6.755 6.965 6.965 1.488.067 1.99.083 5.773.083s4.285-.016 5.773-.083c4.721-.21 6.755-2.239 6.965-6.965.067-1.488.083-1.99.083-5.773s-.016-4.285-.083-5.773c-.21-4.722-2.239-6.755-6.965-6.965C16.285.016 15.784 0 12 0zm0 14.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z"/></svg>
|
| 315 |
+
</a>
|
| 316 |
+
</div>
|
| 317 |
+
</div>
|
| 318 |
+
|
| 319 |
+
<div>
|
| 320 |
+
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Plateforme</h3>
|
| 321 |
+
<ul class="space-y-3 text-gray-500 dark:text-gray-400">
|
| 322 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 323 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 324 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 325 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 326 |
+
</ul>
|
| 327 |
+
</div>
|
| 328 |
+
|
| 329 |
+
<div>
|
| 330 |
+
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Légal</h3>
|
| 331 |
+
<ul class="space-y-3 text-gray-500 dark:text-gray-400">
|
| 332 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 333 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 334 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 335 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 336 |
+
</ul>
|
| 337 |
+
</div>
|
| 338 |
+
|
| 339 |
+
<div class="col-span-2 md:col-span-1">
|
| 340 |
+
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Ressources</h3>
|
| 341 |
+
<ul class="space-y-3 text-gray-500 dark:text-gray-400">
|
| 342 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 343 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 344 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 345 |
+
</ul>
|
| 346 |
+
</div>
|
| 347 |
+
|
| 348 |
+
</div>
|
| 349 |
+
|
| 350 |
+
<div class="mt-10 pt-6 border-t border-gray-200 dark:border-gray-800 text-center text-gray-500 text-sm">
|
| 351 |
+
© 2024 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 352 |
+
</div>
|
| 353 |
+
</div>
|
| 354 |
+
</footer>
|
| 355 |
+
|
| 356 |
+
</body>
|
| 357 |
+
</html>
|
templates/connexion.html
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Connexion - Nexus</title>
|
| 7 |
+
<link rel="stylesheet"
|
| 8 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 9 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 10 |
+
<style>
|
| 11 |
+
body { font-family: 'Inter', sans-serif; }
|
| 12 |
+
|
| 13 |
+
/* Transition pour un effet doux des couleurs */
|
| 14 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 15 |
+
|
| 16 |
+
/* Style et positionnement du bouton */
|
| 17 |
+
.theme-switch {
|
| 18 |
+
background: none;
|
| 19 |
+
border: none;
|
| 20 |
+
cursor: pointer;
|
| 21 |
+
font-size: 24px;
|
| 22 |
+
transition: color 0.2s;
|
| 23 |
+
position: absolute;
|
| 24 |
+
top: 1rem;
|
| 25 |
+
right: 1rem;
|
| 26 |
+
z-index: 10;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Définir les Variables de Thème (Mise à jour pour être similaire à inscription.html) */
|
| 30 |
+
/* Mode Sombre (Défaut : noir très foncé #121212) */
|
| 31 |
+
:root, .dark {
|
| 32 |
+
--bg-page: #121212;
|
| 33 |
+
--bg-card: #1E1E1E;
|
| 34 |
+
--text-color: #FFFFFF; /* Texte général blanc en mode sombre */
|
| 35 |
+
--input-bg: #2C2C2C;
|
| 36 |
+
--border-color: #383838;
|
| 37 |
+
--primary-color: #3B82F6;
|
| 38 |
+
--primary-hover: #2563EB;
|
| 39 |
+
--error-color: #DC2626;
|
| 40 |
+
}
|
| 41 |
+
/* Mode Clair */
|
| 42 |
+
.light {
|
| 43 |
+
--bg-page: #F5F5F5;
|
| 44 |
+
--bg-card: #FFFFFF;
|
| 45 |
+
--text-color: #000000; /* Texte général noir foncé en mode clair */
|
| 46 |
+
--input-bg: #FFFFFF;
|
| 47 |
+
--border-color: #D1D5DB;
|
| 48 |
+
--primary-color: #3B82F6;
|
| 49 |
+
--primary-hover: #2563EB;
|
| 50 |
+
--error-color: #DC2626;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Appliquer les variables au body et aux éléments */
|
| 54 |
+
.bg-page-var { background-color: var(--bg-page); }
|
| 55 |
+
.bg-card-var { background-color: var(--bg-card); }
|
| 56 |
+
.text-color-var { color: var(--text-color); }
|
| 57 |
+
.bg-input-var { background-color: var(--input-bg); }
|
| 58 |
+
.border-color-var { border-color: var(--border-color); }
|
| 59 |
+
.text-primary-color-var { color: var(--primary-color); }
|
| 60 |
+
.bg-primary-color-var { background-color: var(--primary-color); }
|
| 61 |
+
.hover\:text-primary-hover-var:hover { color: var(--primary-hover); }
|
| 62 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color); }
|
| 63 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color); }
|
| 64 |
+
|
| 65 |
+
/* Forcer le texte saisi dans les champs de formulaire en noir foncé (#000000) */
|
| 66 |
+
input[type="text"],
|
| 67 |
+
input[type="email"],
|
| 68 |
+
input[type="password"] {
|
| 69 |
+
color: #000000 !important;
|
| 70 |
+
}
|
| 71 |
+
</style>
|
| 72 |
+
</head>
|
| 73 |
+
<body class="bg-page-var transition-colors-theme min-h-screen flex items-center justify-center p-4">
|
| 74 |
+
|
| 75 |
+
<button id="theme-toggle" class="theme-switch text-color-var hover:text-primary-color-var transition-colors-theme">
|
| 76 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 77 |
+
</button>
|
| 78 |
+
|
| 79 |
+
<div class="w-full max-w-6xl flex flex-col md:flex-row shadow-2xl rounded-lg overflow-hidden">
|
| 80 |
+
|
| 81 |
+
<div class="hidden md:block md:w-1/2 bg-primary-color-var p-12 flex flex-col justify-center items-center text-white transition-colors-theme">
|
| 82 |
+
<svg class="w-32 h-32 mb-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
| 83 |
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15a4 4 0 01-4-4V7a4 4 0 118 0v4a4 4 0 01-4 4z"/>
|
| 84 |
+
</svg>
|
| 85 |
+
<h3 class="text-4xl font-extrabold mb-4 text-center">Bienvenue de Retour</h3>
|
| 86 |
+
<p class="text-center text-lg">Veuillez vous connecter pour accéder à votre tableau de bord.</p>
|
| 87 |
+
</div>
|
| 88 |
+
|
| 89 |
+
<div class="w-full md:w-1/2 bg-card-var transition-colors-theme p-8 md:p-12">
|
| 90 |
+
<h2 class="text-3xl font-bold text-center text-color-var mb-8 transition-colors-theme">Connexion</h2>
|
| 91 |
+
|
| 92 |
+
<p id="message" class="text-center text-red-500 mb-4"></p>
|
| 93 |
+
|
| 94 |
+
<form id="loginForm">
|
| 95 |
+
<div class="mb-4">
|
| 96 |
+
<label for="username" class="block text-sm font-medium text-color-var">Nom d'utilisateur ou Email</label>
|
| 97 |
+
<input type="text" id="username" name="username" placeholder="Votre nom d'utilisateur ou email" required
|
| 98 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 99 |
+
</div>
|
| 100 |
+
|
| 101 |
+
<div class="mb-4">
|
| 102 |
+
<label for="password" class="block text-sm font-medium text-color-var">Mot de Passe</label>
|
| 103 |
+
<input type="password" id="password" name="password" placeholder="Votre mot de passe" required
|
| 104 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 105 |
+
</div>
|
| 106 |
+
|
| 107 |
+
<div class="flex items-center justify-between mb-6">
|
| 108 |
+
<a href="/mot-de-passe-oublie" class="text-sm font-medium text-primary-color-var hover:text-primary-hover-var transition-colors-theme">
|
| 109 |
+
Mot de passe oublié ?
|
| 110 |
+
</a>
|
| 111 |
+
<a href="/inscription" class="text-sm font-medium text-primary-color-var hover:text-primary-hover-var transition-colors-theme">
|
| 112 |
+
Pas de compte? S'inscrire
|
| 113 |
+
</a>
|
| 114 |
+
</div>
|
| 115 |
+
|
| 116 |
+
<button type="submit"
|
| 117 |
+
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-color-var hover:bg-primary-hover-var focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-color-var transition duration-150 ease-in-out">
|
| 118 |
+
Se Connecter
|
| 119 |
+
</button>
|
| 120 |
+
</form>
|
| 121 |
+
</div>
|
| 122 |
+
</div>
|
| 123 |
+
|
| 124 |
+
<script>
|
| 125 |
+
const form = document.getElementById('loginForm');
|
| 126 |
+
const message = document.getElementById('message');
|
| 127 |
+
|
| 128 |
+
form.addEventListener('submit', async (e) => {
|
| 129 |
+
e.preventDefault();
|
| 130 |
+
message.textContent = 'Connexion en cours...';
|
| 131 |
+
message.className = 'text-gray-500 mb-4';
|
| 132 |
+
|
| 133 |
+
const formData = {
|
| 134 |
+
username: form.username.value,
|
| 135 |
+
password: form.password.value,
|
| 136 |
+
};
|
| 137 |
+
|
| 138 |
+
try {
|
| 139 |
+
const response = await fetch('/api/login', {
|
| 140 |
+
method: 'POST',
|
| 141 |
+
headers: { 'Content-Type': 'application/json' },
|
| 142 |
+
body: JSON.stringify(formData)
|
| 143 |
+
});
|
| 144 |
+
|
| 145 |
+
const data = await response.json();
|
| 146 |
+
|
| 147 |
+
if (data.status === 'Success') {
|
| 148 |
+
message.textContent = data.message + " Redirection vers le tableau de bord...";
|
| 149 |
+
message.className = 'text-green-500 mb-4';
|
| 150 |
+
// REDIRECTION AUTOMATIQUE VERS LE DASHBOARD
|
| 151 |
+
setTimeout(() => {
|
| 152 |
+
window.location.href = '/dashboard';
|
| 153 |
+
}, 1500);
|
| 154 |
+
} else {
|
| 155 |
+
message.textContent = 'Erreur : ' + (data.message || 'Échec de la connexion.');
|
| 156 |
+
message.className = 'text-red-500 mb-4';
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
} catch (error) {
|
| 160 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 161 |
+
message.textContent = 'Erreur de connexion au serveur.';
|
| 162 |
+
message.className = 'text-red-500 mb-4';
|
| 163 |
+
}
|
| 164 |
+
});
|
| 165 |
+
|
| 166 |
+
// Logique du thème (conservée pour l'esthétique)
|
| 167 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 168 |
+
const html = document.documentElement;
|
| 169 |
+
|
| 170 |
+
const updateIcon = () => {
|
| 171 |
+
const icon = themeToggle.querySelector('.material-symbols-rounded');
|
| 172 |
+
if (html.classList.contains('light')) {
|
| 173 |
+
icon.textContent = 'light_mode';
|
| 174 |
+
} else {
|
| 175 |
+
icon.textContent = 'dark_mode';
|
| 176 |
+
}
|
| 177 |
+
};
|
| 178 |
+
|
| 179 |
+
const savedTheme = localStorage.getItem('theme');
|
| 180 |
+
if (savedTheme === 'light') {
|
| 181 |
+
html.classList.remove('dark');
|
| 182 |
+
html.classList.add('light');
|
| 183 |
+
} else {
|
| 184 |
+
html.classList.add('dark');
|
| 185 |
+
html.classList.remove('light');
|
| 186 |
+
}
|
| 187 |
+
updateIcon();
|
| 188 |
+
|
| 189 |
+
themeToggle.addEventListener('click', () => {
|
| 190 |
+
if (html.classList.contains('dark')) {
|
| 191 |
+
html.classList.remove('dark');
|
| 192 |
+
html.classList.add('light');
|
| 193 |
+
localStorage.setItem('theme', 'light');
|
| 194 |
+
} else {
|
| 195 |
+
html.classList.remove('light');
|
| 196 |
+
html.classList.add('dark');
|
| 197 |
+
localStorage.setItem('theme', 'dark');
|
| 198 |
+
}
|
| 199 |
+
updateIcon();
|
| 200 |
+
});
|
| 201 |
+
</script>
|
| 202 |
+
</body>
|
| 203 |
+
</html>
|
templates/create_project.html
ADDED
|
@@ -0,0 +1,860 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Mailix | Éditeur de Code - Pro</title>
|
| 7 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.css">
|
| 15 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/theme/monokai.min.css">
|
| 16 |
+
|
| 17 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
|
| 18 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/xml/xml.min.js"></script>
|
| 19 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/javascript/javascript.min.js"></script>
|
| 20 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/css/css.min.js"></script>
|
| 21 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/htmlmixed/htmlmixed.min.js"></script>
|
| 22 |
+
|
| 23 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/python/python.min.js"></script>
|
| 24 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/php/php.min.js"></script>
|
| 25 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/clike/clike.min.js"></script>
|
| 26 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/sql/sql.min.js"></script>
|
| 27 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/markdown/markdown.min.js"></script>
|
| 28 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/shell/shell.min.js"></script>
|
| 29 |
+
|
| 30 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/typescript/typescript.min.js"></script>
|
| 31 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/go/go.min.js"></script>
|
| 32 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/yaml/yaml.min.js"></script>
|
| 33 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/rust/rust.min.js"></script>
|
| 34 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/stex/stex.min.js"></script>
|
| 35 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/meta.js"></script> </head>
|
| 36 |
+
|
| 37 |
+
<style>
|
| 38 |
+
/* Configuration de la police Inter */
|
| 39 |
+
html, body {
|
| 40 |
+
font-family: 'Inter', sans-serif;
|
| 41 |
+
height: 100vh; /* Utiliser 100vh pour garantir la hauteur de la fenêtre */
|
| 42 |
+
overflow: hidden; /* Supprimer le défilement de l'écran principal */
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
/* Transition pour un effet doux des couleurs */
|
| 46 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 47 |
+
|
| 48 |
+
/* Définir les Variables de Thème - UNIQUEMENT Mode Sombre (Défaut) */
|
| 49 |
+
:root, .dark {
|
| 50 |
+
--bg-page: #121212;
|
| 51 |
+
--bg-card: #1E1E1E;
|
| 52 |
+
--bg-sidebar: #1E1E1E;
|
| 53 |
+
--bg-sidebar-active: #2C2C2C;
|
| 54 |
+
--border-sidebar: #383838;
|
| 55 |
+
--text-color: #FFFFFF;
|
| 56 |
+
--text-secondary: #D1D5DB;
|
| 57 |
+
--text-link: #3B82F6;
|
| 58 |
+
--text-link-hover: #60A5FA;
|
| 59 |
+
--input-bg: #2C2C2C;
|
| 60 |
+
--input-border: #4B5563;
|
| 61 |
+
--input-text-key: #6EE7B7;
|
| 62 |
+
--primary-color: #3B82F6;
|
| 63 |
+
--primary-hover: #2563EB;
|
| 64 |
+
--warning-bg: #451A03;
|
| 65 |
+
--warning-border: #78350F;
|
| 66 |
+
--warning-text: #FBBF24;
|
| 67 |
+
--editor-tab-bg: #1E1E1E; /* Fond des onglets de l'éditeur */
|
| 68 |
+
--editor-tab-active-bg: #2C2C2C; /* Fond de l'onglet actif */
|
| 69 |
+
--status-bar-bg: #007ACC; /* Bleu VS Code pour la barre de statut */
|
| 70 |
+
}
|
| 71 |
+
/* Mode Clair (Supprimé selon le plan) */
|
| 72 |
+
|
| 73 |
+
/* Appliquer les variables au body et aux éléments (Conservées) */
|
| 74 |
+
.bg-page-var { background-color: var(--bg-page); }
|
| 75 |
+
.bg-card-var { background-color: var(--bg-card); }
|
| 76 |
+
.bg-sidebar-var { background-color: var(--bg-sidebar); }
|
| 77 |
+
.border-sidebar-var { border-color: var(--border-sidebar); }
|
| 78 |
+
.text-color-var { color: var(--text-color); }
|
| 79 |
+
.text-secondary-var { color: var(--text-secondary); }
|
| 80 |
+
.text-link-var { color: var(--text-link); }
|
| 81 |
+
.hover\:text-link-hover-var:hover { color: var(--text-link-hover); }
|
| 82 |
+
.bg-input-var { background-color: var(--input-bg); }
|
| 83 |
+
.border-input-var { border-color: var(--input-border); }
|
| 84 |
+
.text-input-key-var { color: var(--input-text-key); }
|
| 85 |
+
.bg-primary-color-var { background-color: var(--primary-color); }
|
| 86 |
+
.hover\:bg-primary-hover-var:hover { background-color: var(--primary-hover); }
|
| 87 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color); }
|
| 88 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color); }
|
| 89 |
+
.bg-sidebar-active-var { background-color: var(--bg-sidebar-active); }
|
| 90 |
+
.bg-warning-var { background-color: var(--warning-bg); }
|
| 91 |
+
.border-warning-var { border-color: var(--warning-border); }
|
| 92 |
+
.text-warning-var { color: var(--warning-text); }
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
/* Styles pour les sidebars - FIXES */
|
| 96 |
+
.sidebar {
|
| 97 |
+
transition: transform 0.3s ease-in-out;
|
| 98 |
+
position: fixed;
|
| 99 |
+
top: 0;
|
| 100 |
+
z-index: 30;
|
| 101 |
+
height: 100vh;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
/* Sidebar Gauche - Masquée par défaut sur toutes les tailles */
|
| 105 |
+
.sidebar-left {
|
| 106 |
+
transform: translateX(-100%);
|
| 107 |
+
left: 0;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
.sidebar-left.open {
|
| 111 |
+
transform: translateX(0);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/* FIX 1.1: Sidebar Droite - Masquée par défaut, positionnée à droite */
|
| 115 |
+
.sidebar-right {
|
| 116 |
+
transform: translateX(100%);
|
| 117 |
+
right: 0;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
.sidebar-right.open {
|
| 121 |
+
transform: translateX(0);
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
/* Conteneur principal pour décaler le contenu sur les grands écrans (lg) */
|
| 125 |
+
@media (min-width: 1024px) {
|
| 126 |
+
.main-content {
|
| 127 |
+
margin-left: 0;
|
| 128 |
+
margin-right: 0;
|
| 129 |
+
}
|
| 130 |
+
/* Décalage si sidebar gauche ouverte */
|
| 131 |
+
.main-content.sidebar-left-open {
|
| 132 |
+
margin-left: 256px;
|
| 133 |
+
}
|
| 134 |
+
/* Décalage si sidebar droite ouverte */
|
| 135 |
+
.main-content.sidebar-right-open {
|
| 136 |
+
margin-right: 256px;
|
| 137 |
+
}
|
| 138 |
+
/* Décalage si les deux sidebars sont ouvertes */
|
| 139 |
+
.main-content.sidebar-left-open.sidebar-right-open {
|
| 140 |
+
margin-left: 256px;
|
| 141 |
+
margin-right: 256px;
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
/* Ajustement du bouton de Thème (Supprimé) */
|
| 146 |
+
.theme-switch {
|
| 147 |
+
display: none;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
/* Styles Spécifiques à l'Éditeur */
|
| 151 |
+
.editor-container {
|
| 152 |
+
/* Maintient la disposition en colonne pour header, tabs, editor, footer */
|
| 153 |
+
display: flex;
|
| 154 |
+
flex-direction: column;
|
| 155 |
+
/* Le conteneur s'étire maintenant grâce au body flex-column */
|
| 156 |
+
height: 100%;
|
| 157 |
+
flex-grow: 1; /* Permet au main-content de prendre l'espace restant dans la ligne flex body */
|
| 158 |
+
padding-top: 0;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
/* FIX 3: Réduction du padding du header */
|
| 162 |
+
#main-header {
|
| 163 |
+
padding-top: 0.5rem; /* p-2 */
|
| 164 |
+
padding-bottom: 0.5rem; /* p-2 */
|
| 165 |
+
padding-left: 1rem; /* px-4 */
|
| 166 |
+
padding-right: 1rem; /* px-4 */
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
/* FIX 2.2: Le wrapper de l'éditeur prend l'espace restant dans la colonne flex */
|
| 170 |
+
#code-editor-wrapper {
|
| 171 |
+
flex-grow: 1;
|
| 172 |
+
overflow: hidden; /* Empêche le CodeMirror de faire défiler le parent */
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
/* CodeMirror Styling - Pour un look sombre VS Code (Monokai) */
|
| 176 |
+
.CodeMirror {
|
| 177 |
+
flex-grow: 1;
|
| 178 |
+
height: 100% !important; /* Essentiel pour que le défilement CodeMirror fonctionne */
|
| 179 |
+
font-size: 14px;
|
| 180 |
+
line-height: 1.5;
|
| 181 |
+
background: #272822; /* Fond Monokai */
|
| 182 |
+
color: #f8f8f2;
|
| 183 |
+
border-top: 1px solid var(--border-sidebar);
|
| 184 |
+
border-bottom: 1px solid var(--border-sidebar);
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
/* Style de la barre d'onglets */
|
| 188 |
+
#tab-bar {
|
| 189 |
+
background-color: var(--editor-tab-bg);
|
| 190 |
+
border-bottom: 1px solid var(--border-sidebar);
|
| 191 |
+
min-height: 40px;
|
| 192 |
+
padding-left: 10px;
|
| 193 |
+
/* MODIFICATION 2.1 - 2.3: Permet le défilement horizontal */
|
| 194 |
+
overflow-x: auto;
|
| 195 |
+
white-space: nowrap; /* Empêche le wrapping des onglets */
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
.tab-item {
|
| 199 |
+
/* MODIFICATION 2.2: S'assure que les onglets ne se rétrécissent pas pour le défilement */
|
| 200 |
+
flex-shrink: 0;
|
| 201 |
+
display: inline-flex; /* Utilisation de inline-flex au lieu de flex pour un meilleur comportement avec white-space: nowrap */
|
| 202 |
+
align-items: center;
|
| 203 |
+
padding: 8px 15px;
|
| 204 |
+
border-right: 1px solid var(--border-sidebar);
|
| 205 |
+
cursor: pointer;
|
| 206 |
+
color: var(--text-secondary);
|
| 207 |
+
font-size: 0.875rem;
|
| 208 |
+
transition: background-color 0.2s;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
.tab-item.active {
|
| 212 |
+
background-color: var(--editor-tab-active-bg);
|
| 213 |
+
color: var(--text-color);
|
| 214 |
+
position: relative;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
.tab-item:hover:not(.active) {
|
| 218 |
+
background-color: var(--bg-sidebar-active);
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
.tab-close {
|
| 222 |
+
margin-left: 8px;
|
| 223 |
+
font-size: 14px;
|
| 224 |
+
color: var(--text-secondary);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
/* Style de la barre de statut */
|
| 228 |
+
#status-bar {
|
| 229 |
+
background-color: var(--status-bar-bg);
|
| 230 |
+
color: white;
|
| 231 |
+
min-height: 25px;
|
| 232 |
+
font-size: 0.75rem;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
/* Modale */
|
| 236 |
+
.modal {
|
| 237 |
+
position: fixed;
|
| 238 |
+
top: 0;
|
| 239 |
+
left: 0;
|
| 240 |
+
width: 100%;
|
| 241 |
+
height: 100%;
|
| 242 |
+
background-color: rgba(0, 0, 0, 0.7);
|
| 243 |
+
display: none;
|
| 244 |
+
justify-content: center;
|
| 245 |
+
align-items: center;
|
| 246 |
+
z-index: 50;
|
| 247 |
+
}
|
| 248 |
+
.modal.open {
|
| 249 |
+
display: flex;
|
| 250 |
+
}
|
| 251 |
+
.modal-content {
|
| 252 |
+
padding: 1.5rem;
|
| 253 |
+
border-radius: 0.5rem;
|
| 254 |
+
width: 90%;
|
| 255 |
+
max-width: 400px;
|
| 256 |
+
}
|
| 257 |
+
.input-text {
|
| 258 |
+
border-width: 1px;
|
| 259 |
+
padding: 0.75rem;
|
| 260 |
+
border-radius: 0.375rem;
|
| 261 |
+
width: 100%;
|
| 262 |
+
font-size: 1rem;
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
/* Masquer la marge du main-content sur mobile pour l'éditeur */
|
| 267 |
+
@media (max-width: 1023px) {
|
| 268 |
+
.main-content {
|
| 269 |
+
padding: 0;
|
| 270 |
+
}
|
| 271 |
+
.editor-container {
|
| 272 |
+
/* Calcule la hauteur totale - (Header + barre de statut + barre d'onglets) pour l'éditeur */
|
| 273 |
+
/* Cette règle est moins critique si flex-grow est appliqué correctement */
|
| 274 |
+
height: calc(100vh - 40px - 40px - 25px); /* Environ */
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
</style>
|
| 278 |
+
</head>
|
| 279 |
+
|
| 280 |
+
<body class="bg-page-var text-color-var min-h-screen transition-colors-theme flex flex-col">
|
| 281 |
+
|
| 282 |
+
<aside id="sidebar-left" class="sidebar sidebar-left w-64 bg-sidebar-var border-r border-sidebar-var p-6 flex flex-col transition-colors-theme">
|
| 283 |
+
|
| 284 |
+
<div class="flex items-center mb-6 shrink-0">
|
| 285 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 286 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Mailix</span>
|
| 287 |
+
</div>
|
| 288 |
+
|
| 289 |
+
<div class="flex-grow overflow-y-auto pr-2" id="scrollable-nav-container">
|
| 290 |
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-secondary-var mb-2">Fichiers Ouverts</h3>
|
| 291 |
+
<nav id="file-explorer" class="space-y-1 pb-4 border-b border-sidebar-var/50 mb-4">
|
| 292 |
+
</nav>
|
| 293 |
+
|
| 294 |
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-secondary-var mb-2">Navigation</h3>
|
| 295 |
+
<nav class="space-y-3 pb-4">
|
| 296 |
+
<a href="{{ url_for('user_bp.dashboard') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 297 |
+
<span class="material-symbols-rounded">dashboard</span>
|
| 298 |
+
<span class="ml-3">Dashboard</span>
|
| 299 |
+
</a>
|
| 300 |
+
|
| 301 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 302 |
+
<span class="material-symbols-rounded">person</span>
|
| 303 |
+
<span class="ml-3">Profil</span>
|
| 304 |
+
</a>
|
| 305 |
+
<a href="/parametres" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 306 |
+
<span class="material-symbols-rounded">settings</span> <span class="ml-3">Paramètres</span>
|
| 307 |
+
</a>
|
| 308 |
+
|
| 309 |
+
<a href="/aide" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 310 |
+
<span class="material-symbols-rounded">help</span>
|
| 311 |
+
<span class="ml-3">Aide & Support</span>
|
| 312 |
+
</a>
|
| 313 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 314 |
+
<span class="material-symbols-rounded">person</span>
|
| 315 |
+
<span class="ml-3">Profil</span>
|
| 316 |
+
</a>
|
| 317 |
+
|
| 318 |
+
<a href="/tarifs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 319 |
+
<span class="material-symbols-rounded">payments</span>
|
| 320 |
+
<span class="ml-3">Tarifs</span>
|
| 321 |
+
</a>
|
| 322 |
+
<a href="/statut" class="flex items-center p-3 bg-sidebar-active-var text-color-var rounded-lg transition duration-150 transition-colors-theme">
|
| 323 |
+
<span class="material-symbols-rounded">monitor_heart</span>
|
| 324 |
+
<span class="ml-3">Statut de l'API</span>
|
| 325 |
+
</a>
|
| 326 |
+
<a href="{{ url_for('user_bp.deconnexion') }}" id="logout-button-sidebar" class="flex items-center p-3 text-red-500 hover:text-red-400 hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 327 |
+
<span class="material-symbols-rounded">deconnexion</span>
|
| 328 |
+
<span class="ml-3">Déconnexion</span>
|
| 329 |
+
</a>
|
| 330 |
+
</nav>
|
| 331 |
+
</div>
|
| 332 |
+
|
| 333 |
+
<div class="mt-auto pt-4 text-xs text-secondary-var transition-colors-theme border-t border-sidebar-var/50 shrink-0">
|
| 334 |
+
<p>Connecté en tant que: <span class="font-semibold text-color-var transition-colors-theme">{{ user.email if user and user.email else 'Chargement...' }}</span></p>
|
| 335 |
+
<p>Plan: <span class="font-semibold text-color-var transition-colors-theme">{{ (user.plan | upper) if user and user.plan else 'GRATUIT' }}</span></p>
|
| 336 |
+
</div>
|
| 337 |
+
|
| 338 |
+
</aside>
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
<aside id="sidebar-right" class="sidebar sidebar-right w-64 bg-sidebar-var border-l border-sidebar-var p-4 flex flex-col transition-colors-theme overflow-y-auto">
|
| 342 |
+
<div class="flex items-center mb-4 shrink-0 border-b border-sidebar-var/50 pb-2">
|
| 343 |
+
<span class="material-symbols-rounded text-xl mr-2">settings</span>
|
| 344 |
+
<span class="text-lg font-semibold text-color-var">Outils & Paramètres</span>
|
| 345 |
+
</div>
|
| 346 |
+
|
| 347 |
+
<div id="editor-settings-section" class="mb-6">
|
| 348 |
+
<h4 class="flex items-center text-sm font-bold uppercase tracking-wider text-secondary-var mb-2">
|
| 349 |
+
<span class="material-symbols-rounded text-base mr-1">settings</span>
|
| 350 |
+
Paramètres de l'Éditeur
|
| 351 |
+
</h4>
|
| 352 |
+
<div class="space-y-3 p-2 bg-sidebar-active-var rounded-lg">
|
| 353 |
+
<div>
|
| 354 |
+
<label class="block text-xs font-medium text-secondary-var mb-1">Thème du Code</label>
|
| 355 |
+
<select class="w-full bg-input-var text-color-var p-2 rounded-md border border-input-var text-sm">
|
| 356 |
+
<option selected>Monokai (Défaut)</option>
|
| 357 |
+
<option>VS Light</option>
|
| 358 |
+
<option>Dracula</option>
|
| 359 |
+
</select>
|
| 360 |
+
</div>
|
| 361 |
+
<div>
|
| 362 |
+
<label class="block text-xs font-medium text-secondary-var mb-1">Taille de Police</label>
|
| 363 |
+
<input type="range" min="10" max="20" value="14" class="w-full h-1 bg-primary-color-var rounded-lg appearance-none cursor-pointer">
|
| 364 |
+
<p class="text-xs text-secondary-var mt-1">Taille actuelle: 14px</p>
|
| 365 |
+
</div>
|
| 366 |
+
<div>
|
| 367 |
+
<label class="block text-xs font-medium text-secondary-var mb-1">Indentation</label>
|
| 368 |
+
<select class="w-full bg-input-var text-color-var p-2 rounded-md border border-input-var text-sm">
|
| 369 |
+
<option selected>Espaces (4)</option>
|
| 370 |
+
<option>Espaces (2)</option>
|
| 371 |
+
<option>Tabulations</option>
|
| 372 |
+
</select>
|
| 373 |
+
</div>
|
| 374 |
+
</div>
|
| 375 |
+
</div>
|
| 376 |
+
|
| 377 |
+
<div id="minimap-section" class="mb-6">
|
| 378 |
+
<h4 class="flex items-center text-sm font-bold uppercase tracking-wider text-secondary-var mb-2">
|
| 379 |
+
<span class="material-symbols-rounded text-base mr-1">map</span>
|
| 380 |
+
Aperçu du Code (Minimap)
|
| 381 |
+
</h4>
|
| 382 |
+
<div class="h-20 bg-input-var border border-input-border rounded-lg flex items-center justify-center text-xs text-secondary-var/70">
|
| 383 |
+
[Zone de Minimap Simulé]
|
| 384 |
+
</div>
|
| 385 |
+
</div>
|
| 386 |
+
|
| 387 |
+
<div id="inspection-section" class="flex-grow">
|
| 388 |
+
<h4 class="flex items-center text-sm font-bold uppercase tracking-wider text-secondary-var mb-2">
|
| 389 |
+
<span class="material-symbols-rounded text-base mr-1">search</span>
|
| 390 |
+
Inspection/Propriétés
|
| 391 |
+
</h4>
|
| 392 |
+
<div class="p-3 bg-sidebar-active-var rounded-lg h-full overflow-y-auto text-xs space-y-2">
|
| 393 |
+
<p class="font-semibold text-color-var">Élément sélectionné: <body></p>
|
| 394 |
+
<p><span class="text-input-key-var">background-color:</span> var(--bg-page);</p>
|
| 395 |
+
<p><span class="text-input-key-var">color:</span> var(--text-color);</p>
|
| 396 |
+
<p class="text-secondary-var mt-4">[Aide Contextuelle pour la balise HTML 'body']</p>
|
| 397 |
+
</div>
|
| 398 |
+
</div>
|
| 399 |
+
</aside>
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
<div id="main-content" class="main-content flex-grow transition-colors-theme editor-container">
|
| 403 |
+
|
| 404 |
+
<header id="main-header" class="flex justify-between items-center bg-page-var p-2 border-b border-sidebar-var shrink-0">
|
| 405 |
+
<button id="sidebar-left-toggle" class="mobile-toggle-button p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme">
|
| 406 |
+
<span class="material-symbols-rounded text-color-var">menu</span>
|
| 407 |
+
</button>
|
| 408 |
+
<div class="flex items-center">
|
| 409 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 410 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Mailix Editor</span>
|
| 411 |
+
</div>
|
| 412 |
+
<button id="sidebar-right-toggle" class="mobile-toggle-button p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme" title="Outils et Paramètres">
|
| 413 |
+
<span class="material-symbols-rounded text-color-var">more_vert</span>
|
| 414 |
+
</button>
|
| 415 |
+
</header>
|
| 416 |
+
|
| 417 |
+
<div id="tab-bar" class="flex items-center overflow-x-auto shrink-0">
|
| 418 |
+
<button id="add-tab-button" class="flex items-center p-2 text-secondary-var hover:text-color-var transition-colors-theme" title="Ajouter un nouveau fichier">
|
| 419 |
+
<span class="material-symbols-rounded text-xl">add</span>
|
| 420 |
+
</button>
|
| 421 |
+
<button id="import-button" class="flex items-center p-2 text-secondary-var hover:text-color-var transition-colors-theme" title="Importer un fichier local">
|
| 422 |
+
<span class="material-symbols-rounded text-xl">file_upload</span>
|
| 423 |
+
</button>
|
| 424 |
+
<input type="file" id="file-input" class="hidden" />
|
| 425 |
+
|
| 426 |
+
<button id="save-button" class="ml-auto flex items-center p-2 text-link-var hover:text-link-hover-var transition-colors-theme font-semibold border-l border-sidebar-var" title="Sauvegarder localement">
|
| 427 |
+
<span class="material-symbols-rounded text-xl mr-1">save</span>
|
| 428 |
+
Sauvegarder
|
| 429 |
+
</button>
|
| 430 |
+
</div>
|
| 431 |
+
|
| 432 |
+
<div id="code-editor-wrapper">
|
| 433 |
+
<textarea id="code-editor-textarea" style="display: none;">
|
| 434 |
+
<!DOCTYPE html>
|
| 435 |
+
<html lang="fr">
|
| 436 |
+
<head>
|
| 437 |
+
<meta charset="UTF-8">
|
| 438 |
+
<title>Mon Nouveau Projet</title>
|
| 439 |
+
<link rel="stylesheet" href="style.css">
|
| 440 |
+
</head>
|
| 441 |
+
<body>
|
| 442 |
+
<h1>Bienvenue dans l'Éditeur Mailix</h1>
|
| 443 |
+
<p>Ce code est mis en évidence par CodeMirror.</p>
|
| 444 |
+
</body>
|
| 445 |
+
</html>
|
| 446 |
+
</textarea>
|
| 447 |
+
</div>
|
| 448 |
+
|
| 449 |
+
<footer id="status-bar" class="flex items-center justify-between px-4 py-0.5 shrink-0">
|
| 450 |
+
<div class="flex items-center space-x-4">
|
| 451 |
+
<span class="material-symbols-rounded text-sm">code</span>
|
| 452 |
+
<span id="status-language">Langage: HTML</span>
|
| 453 |
+
</div>
|
| 454 |
+
<div class="flex items-center space-x-4">
|
| 455 |
+
<span id="status-encoding">UTF-8</span>
|
| 456 |
+
<span id="status-line-col">Ligne: 1, Col: 1</span>
|
| 457 |
+
</div>
|
| 458 |
+
</footer>
|
| 459 |
+
|
| 460 |
+
</div>
|
| 461 |
+
|
| 462 |
+
<div id="create-file-modal" class="modal">
|
| 463 |
+
<div class="modal-content bg-card-var text-color-var">
|
| 464 |
+
<h2 class="text-xl font-bold mb-4">Créer un Nouveau Fichier</h2>
|
| 465 |
+
<input type="text" id="new-file-name-input" class="input-text bg-input-var border-input-var text-color-var focus:border-primary-color-var focus:ring-1 focus:ring-primary-color-var outline-none mb-4" placeholder="Nom du fichier (ex: index.html, style.css, script.js)" required>
|
| 466 |
+
<div class="flex justify-end space-x-3">
|
| 467 |
+
<button id="cancel-create-file" class="px-4 py-2 text-secondary-var hover:text-color-var rounded-lg transition-colors-theme">Annuler</button>
|
| 468 |
+
<button id="confirm-create-file" class="px-4 py-2 bg-primary-color-var hover:bg-primary-hover-var text-white font-semibold rounded-lg transition-colors-theme">Créer</button>
|
| 469 |
+
</div>
|
| 470 |
+
</div>
|
| 471 |
+
</div>
|
| 472 |
+
|
| 473 |
+
<script>
|
| 474 |
+
// --- PARTIE 1: GESTION DE LA SIDEBAR (Gauche et Droite) ---
|
| 475 |
+
|
| 476 |
+
// Éléments de la Sidebar Gauche
|
| 477 |
+
const sidebarLeftToggle = document.getElementById('sidebar-left-toggle');
|
| 478 |
+
const sidebarLeft = document.getElementById('sidebar-left'); // ID mis à jour
|
| 479 |
+
const mainContent = document.getElementById('main-content');
|
| 480 |
+
|
| 481 |
+
// Éléments de la Sidebar Droite (NOUVEAU)
|
| 482 |
+
const sidebarRightToggle = document.getElementById('sidebar-right-toggle');
|
| 483 |
+
const sidebarRight = document.getElementById('sidebar-right');
|
| 484 |
+
|
| 485 |
+
// Logique pour la Sidebar Gauche
|
| 486 |
+
function toggleSidebarLeft() {
|
| 487 |
+
sidebarLeft.classList.toggle('open');
|
| 488 |
+
// Gérer le décalage du contenu principal sur grand écran (lg)
|
| 489 |
+
if (window.innerWidth >= 1024) {
|
| 490 |
+
mainContent.classList.toggle('sidebar-left-open');
|
| 491 |
+
}
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
// Logique pour la Sidebar Droite (NOUVEAU)
|
| 495 |
+
function toggleSidebarRight() {
|
| 496 |
+
sidebarRight.classList.toggle('open');
|
| 497 |
+
// Gérer le décalage du contenu principal sur grand écran (lg)
|
| 498 |
+
if (window.innerWidth >= 1024) {
|
| 499 |
+
mainContent.classList.toggle('sidebar-right-open');
|
| 500 |
+
}
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
sidebarLeftToggle.addEventListener('click', toggleSidebarLeft);
|
| 504 |
+
sidebarRightToggle.addEventListener('click', toggleSidebarRight); // Lier le nouveau bouton
|
| 505 |
+
|
| 506 |
+
|
| 507 |
+
// Logique de Déconnexion (Conservée)
|
| 508 |
+
document.getElementById('logout-button-sidebar').addEventListener('click', (e) => {
|
| 509 |
+
e.preventDefault();
|
| 510 |
+
window.location.href = e.currentTarget.href;
|
| 511 |
+
});
|
| 512 |
+
|
| 513 |
+
|
| 514 |
+
// --- PARTIE 2: GESTION DE L'ÉDITEUR DE CODE (CodeMirror + Onglets) ---
|
| 515 |
+
|
| 516 |
+
// Structure de données pour les fichiers (V1: Stockage local)
|
| 517 |
+
let files = [
|
| 518 |
+
{ id: 1, name: 'index.html', content: document.getElementById('code-editor-textarea').value, mode: 'htmlmixed', isActive: true },
|
| 519 |
+
{ id: 2, name: 'style.css', content: "body {\n font-family: sans-serif;\n color: #4CAF50; /* Green */\n}", mode: 'css', isActive: false },
|
| 520 |
+
{ id: 3, name: 'script.js', content: "console.log('Editor Ready!');", mode: 'javascript', isActive: false }
|
| 521 |
+
];
|
| 522 |
+
let fileIdCounter = files.length + 1;
|
| 523 |
+
let currentEditor = null; // L'instance CodeMirror
|
| 524 |
+
|
| 525 |
+
const tabBar = document.getElementById('tab-bar');
|
| 526 |
+
const editorTextarea = document.getElementById('code-editor-textarea');
|
| 527 |
+
const statusBarLanguage = document.getElementById('status-language');
|
| 528 |
+
const statusBarLineCol = document.getElementById('status-line-col');
|
| 529 |
+
const fileExplorer = document.getElementById('file-explorer');
|
| 530 |
+
|
| 531 |
+
// Éléments de la modale
|
| 532 |
+
const createFileModal = document.getElementById('create-file-modal');
|
| 533 |
+
const newFileNameInput = document.getElementById('new-file-name-input');
|
| 534 |
+
const confirmCreateFileButton = document.getElementById('confirm-create-file');
|
| 535 |
+
const cancelCreateFileButton = document.getElementById('cancel-create-file');
|
| 536 |
+
|
| 537 |
+
/**
|
| 538 |
+
* Détermine le mode CodeMirror à partir de l'extension du nom de fichier.
|
| 539 |
+
* @param {string} fileName Le nom du fichier.
|
| 540 |
+
* @returns {string} Le mode CodeMirror.
|
| 541 |
+
*/
|
| 542 |
+
|
| 543 |
+
function getModeFromFileExtension(fileName) {
|
| 544 |
+
const ext = fileName.split('.').pop().toLowerCase();
|
| 545 |
+
switch (ext) {
|
| 546 |
+
// Web
|
| 547 |
+
case 'html':
|
| 548 |
+
case 'htm':
|
| 549 |
+
return 'htmlmixed';
|
| 550 |
+
case 'css':
|
| 551 |
+
return 'css';
|
| 552 |
+
case 'js':
|
| 553 |
+
return 'javascript';
|
| 554 |
+
case 'ts':
|
| 555 |
+
return 'typescript'; // Nouveau
|
| 556 |
+
case 'json':
|
| 557 |
+
return 'application/json'; // Nouveau (mode spécifique pour JSON)
|
| 558 |
+
|
| 559 |
+
// Backend / Systèmes
|
| 560 |
+
case 'py':
|
| 561 |
+
return 'python';
|
| 562 |
+
case 'php':
|
| 563 |
+
case 'phtml':
|
| 564 |
+
return 'php';
|
| 565 |
+
case 'go':
|
| 566 |
+
return 'go'; // Nouveau
|
| 567 |
+
case 'rs':
|
| 568 |
+
return 'rust'; // Nouveau
|
| 569 |
+
case 'sh':
|
| 570 |
+
return 'shell';
|
| 571 |
+
|
| 572 |
+
// Langages C-like (Java, C, C++, C#)
|
| 573 |
+
case 'java':
|
| 574 |
+
case 'c':
|
| 575 |
+
case 'cpp':
|
| 576 |
+
case 'cs':
|
| 577 |
+
return 'clike';
|
| 578 |
+
|
| 579 |
+
// Données et Bases de données
|
| 580 |
+
case 'sql':
|
| 581 |
+
return 'sql';
|
| 582 |
+
case 'yaml':
|
| 583 |
+
case 'yml':
|
| 584 |
+
return 'yaml'; // Nouveau
|
| 585 |
+
|
| 586 |
+
// Documentation et autres
|
| 587 |
+
case 'md':
|
| 588 |
+
case 'markdown':
|
| 589 |
+
return 'markdown';
|
| 590 |
+
case 'tex':
|
| 591 |
+
case 'latex':
|
| 592 |
+
return 'stex'; // Nouveau (pour LaTeX)
|
| 593 |
+
|
| 594 |
+
default:
|
| 595 |
+
return 'text/plain'; // Mode texte brut pour les inconnus ou le texte simple
|
| 596 |
+
}
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
|
| 600 |
+
/**
|
| 601 |
+
* Initialise CodeMirror sur le textarea.
|
| 602 |
+
*/
|
| 603 |
+
function initializeEditor(initialContent, mode) {
|
| 604 |
+
if (currentEditor) {
|
| 605 |
+
currentEditor.toTextArea(); // Détruit l'ancienne instance
|
| 606 |
+
currentEditor = null;
|
| 607 |
+
}
|
| 608 |
+
|
| 609 |
+
editorTextarea.value = initialContent;
|
| 610 |
+
|
| 611 |
+
currentEditor = CodeMirror.fromTextArea(editorTextarea, {
|
| 612 |
+
lineNumbers: true,
|
| 613 |
+
mode: mode,
|
| 614 |
+
theme: 'monokai',
|
| 615 |
+
indentUnit: 4,
|
| 616 |
+
tabSize: 4,
|
| 617 |
+
indentWithTabs: false,
|
| 618 |
+
autofocus: true,
|
| 619 |
+
// MODIFICATION 1.2: Désactiver le retour à la ligne pour forcer le défilement horizontal
|
| 620 |
+
lineWrapping: false,
|
| 621 |
+
});
|
| 622 |
+
|
| 623 |
+
// Événement de mise à jour du contenu et de la barre de statut
|
| 624 |
+
currentEditor.on("change", handleEditorChange);
|
| 625 |
+
currentEditor.on("cursorActivity", updateStatusBar);
|
| 626 |
+
|
| 627 |
+
// S'assurer que CodeMirror utilise 100% de la hauteur disponible dans son conteneur parent flexible
|
| 628 |
+
const cmElement = currentEditor.getWrapperElement();
|
| 629 |
+
cmElement.style.height = '100%';
|
| 630 |
+
|
| 631 |
+
updateStatusBar();
|
| 632 |
+
}
|
| 633 |
+
|
| 634 |
+
/**
|
| 635 |
+
* Met à jour le contenu de l'objet fichier actif dans le tableau `files`.
|
| 636 |
+
*/
|
| 637 |
+
function handleEditorChange() {
|
| 638 |
+
if (currentEditor) {
|
| 639 |
+
const activeFile = files.find(f => f.isActive);
|
| 640 |
+
if (activeFile) {
|
| 641 |
+
activeFile.content = currentEditor.getValue();
|
| 642 |
+
}
|
| 643 |
+
}
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
/**
|
| 647 |
+
* Met à jour les indicateurs Ligne/Col dans la barre de statut.
|
| 648 |
+
*/
|
| 649 |
+
function updateStatusBar() {
|
| 650 |
+
if (currentEditor) {
|
| 651 |
+
const cursor = currentEditor.getCursor();
|
| 652 |
+
statusBarLineCol.textContent = `Ligne: ${cursor.line + 1}, Col: ${cursor.ch + 1}`;
|
| 653 |
+
}
|
| 654 |
+
}
|
| 655 |
+
|
| 656 |
+
/**
|
| 657 |
+
* Affiche l'éditeur avec le contenu du fichier sélectionné.
|
| 658 |
+
* @param {number} fileId L'ID du fichier à activer.
|
| 659 |
+
*/
|
| 660 |
+
function setActiveFile(fileId) {
|
| 661 |
+
files.forEach(f => f.isActive = f.id === fileId);
|
| 662 |
+
|
| 663 |
+
const activeFile = files.find(f => f.isActive);
|
| 664 |
+
if (activeFile) {
|
| 665 |
+
// Mise à jour de CodeMirror
|
| 666 |
+
if (currentEditor) {
|
| 667 |
+
currentEditor.setValue(activeFile.content);
|
| 668 |
+
currentEditor.setOption("mode", activeFile.mode);
|
| 669 |
+
currentEditor.focus();
|
| 670 |
+
} else {
|
| 671 |
+
// Initialisation au premier chargement
|
| 672 |
+
initializeEditor(activeFile.content, activeFile.mode);
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
// Mise à jour de la barre de statut
|
| 676 |
+
const modeName = activeFile.mode.includes('html') ? 'HTML' : (activeFile.mode === 'css' ? 'CSS' : 'JavaScript');
|
| 677 |
+
statusBarLanguage.textContent = `Langage: ${modeName}`;
|
| 678 |
+
}
|
| 679 |
+
renderTabs();
|
| 680 |
+
renderFileExplorer(); // Mise à jour de l'explorateur
|
| 681 |
+
}
|
| 682 |
+
|
| 683 |
+
/**
|
| 684 |
+
* Génère et affiche les onglets dans la barre d'onglets.
|
| 685 |
+
*/
|
| 686 |
+
function renderTabs() {
|
| 687 |
+
// Enlever tous les onglets existants sauf le bouton '+' et 'Sauvegarder' et 'Importer'
|
| 688 |
+
// On cible spécifiquement les éléments avec la classe 'tab-item'
|
| 689 |
+
const existingTabs = tabBar.querySelectorAll('.tab-item');
|
| 690 |
+
existingTabs.forEach(tab => tab.remove());
|
| 691 |
+
|
| 692 |
+
const saveButton = document.getElementById('save-button');
|
| 693 |
+
|
| 694 |
+
files.forEach(file => {
|
| 695 |
+
const tab = document.createElement('div');
|
| 696 |
+
// 'flex items-center' est conservé mais 'inline-flex' est dans le CSS pour le white-space: nowrap
|
| 697 |
+
tab.className = `tab-item flex items-center ${file.isActive ? 'active' : ''}`;
|
| 698 |
+
tab.dataset.fileId = file.id;
|
| 699 |
+
tab.innerHTML = `
|
| 700 |
+
<span>${file.name}</span>
|
| 701 |
+
<span class="tab-close material-symbols-rounded text-sm hover:text-color-var transition-colors-theme ml-2">close</span>
|
| 702 |
+
`;
|
| 703 |
+
|
| 704 |
+
// Attacher l'onglet avant le bouton Sauvegarder (qui est 'ml-auto')
|
| 705 |
+
// Remarque: La structure des boutons dans le HTML implique que les onglets sont insérés avant le saveButton (qui a ml-auto)
|
| 706 |
+
tabBar.insertBefore(tab, saveButton);
|
| 707 |
+
|
| 708 |
+
// Gérer le clic pour activer l'onglet
|
| 709 |
+
tab.querySelector('span').addEventListener('click', (e) => {
|
| 710 |
+
// Évite de déclencher l'activation si on clique sur l'icône de fermeture
|
| 711 |
+
if (!e.target.classList.contains('tab-close')) {
|
| 712 |
+
setActiveFile(file.id);
|
| 713 |
+
}
|
| 714 |
+
});
|
| 715 |
+
|
| 716 |
+
// Gérer le clic pour fermer l'onglet
|
| 717 |
+
tab.querySelector('.tab-close').addEventListener('click', () => closeFile(file.id));
|
| 718 |
+
});
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
/**
|
| 722 |
+
* Génère et affiche la liste des fichiers dans l'explorateur de fichiers.
|
| 723 |
+
*/
|
| 724 |
+
function renderFileExplorer() {
|
| 725 |
+
fileExplorer.innerHTML = ''; // Nettoyer l'explorateur
|
| 726 |
+
|
| 727 |
+
files.forEach(file => {
|
| 728 |
+
const item = document.createElement('a');
|
| 729 |
+
const isActiveClass = file.isActive ? 'bg-sidebar-active-var text-color-var' : 'text-secondary-var hover:text-color-var hover:bg-sidebar-active-var';
|
| 730 |
+
|
| 731 |
+
item.href = '#';
|
| 732 |
+
item.className = `flex items-center p-2 text-sm rounded-lg transition duration-150 transition-colors-theme ${isActiveClass}`;
|
| 733 |
+
item.dataset.fileId = file.id;
|
| 734 |
+
item.innerHTML = `
|
| 735 |
+
<span class="material-symbols-rounded text-base">insert_drive_file</span>
|
| 736 |
+
<span class="ml-2 truncate">${file.name}</span>
|
| 737 |
+
`;
|
| 738 |
+
|
| 739 |
+
item.addEventListener('click', (e) => {
|
| 740 |
+
e.preventDefault();
|
| 741 |
+
setActiveFile(file.id);
|
| 742 |
+
});
|
| 743 |
+
|
| 744 |
+
fileExplorer.appendChild(item);
|
| 745 |
+
});
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
/**
|
| 749 |
+
* Ajoute un nouveau fichier/onglet.
|
| 750 |
+
* @param {string} fileName Le nom du fichier.
|
| 751 |
+
* @param {string} fileContent Le contenu du fichier (par défaut vide).
|
| 752 |
+
*/
|
| 753 |
+
function createNewFile(fileName, fileContent = "// Nouveau fichier") {
|
| 754 |
+
const mode = getModeFromFileExtension(fileName);
|
| 755 |
+
const newFile = {
|
| 756 |
+
id: fileIdCounter++,
|
| 757 |
+
name: fileName,
|
| 758 |
+
content: fileContent,
|
| 759 |
+
mode: mode,
|
| 760 |
+
isActive: false // Sera activé par setActiveFile
|
| 761 |
+
};
|
| 762 |
+
files.push(newFile);
|
| 763 |
+
setActiveFile(newFile.id);
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
/**
|
| 767 |
+
* Ferme un fichier/onglet.
|
| 768 |
+
* @param {number} fileId L'ID du fichier à fermer.
|
| 769 |
+
*/
|
| 770 |
+
function closeFile(fileId) {
|
| 771 |
+
const index = files.findIndex(f => f.id === fileId);
|
| 772 |
+
if (index === -1) return;
|
| 773 |
+
|
| 774 |
+
const wasActive = files[index].isActive;
|
| 775 |
+
|
| 776 |
+
files.splice(index, 1); // Retire le fichier
|
| 777 |
+
|
| 778 |
+
if (files.length === 0) {
|
| 779 |
+
// Si plus de fichiers, ajoute un fichier vierge
|
| 780 |
+
createNewFile(`untitled-${fileIdCounter}.js`);
|
| 781 |
+
return;
|
| 782 |
+
}
|
| 783 |
+
|
| 784 |
+
if (wasActive) {
|
| 785 |
+
// Active le fichier précédent ou le premier s'il n'y a pas de précédent
|
| 786 |
+
const newActiveFile = files[Math.max(0, index - 1)];
|
| 787 |
+
setActiveFile(newActiveFile.id);
|
| 788 |
+
} else {
|
| 789 |
+
// Si ce n'était pas l'actif, on rafraîchit juste les onglets et l'explorateur
|
| 790 |
+
renderTabs();
|
| 791 |
+
renderFileExplorer();
|
| 792 |
+
}
|
| 793 |
+
}
|
| 794 |
+
|
| 795 |
+
// --- Logique de la Modale de Création de Fichier ---
|
| 796 |
+
document.getElementById('add-tab-button').addEventListener('click', () => {
|
| 797 |
+
newFileNameInput.value = ''; // Réinitialiser l'input
|
| 798 |
+
createFileModal.classList.add('open');
|
| 799 |
+
newFileNameInput.focus();
|
| 800 |
+
});
|
| 801 |
+
|
| 802 |
+
cancelCreateFileButton.addEventListener('click', () => {
|
| 803 |
+
createFileModal.classList.remove('open');
|
| 804 |
+
});
|
| 805 |
+
|
| 806 |
+
confirmCreateFileButton.addEventListener('click', () => {
|
| 807 |
+
const fileName = newFileNameInput.value.trim();
|
| 808 |
+
if (fileName) {
|
| 809 |
+
createNewFile(fileName);
|
| 810 |
+
createFileModal.classList.remove('open');
|
| 811 |
+
} else {
|
| 812 |
+
alert("Veuillez entrer un nom de fichier.");
|
| 813 |
+
}
|
| 814 |
+
});
|
| 815 |
+
|
| 816 |
+
// --- Logique d'Importation de Fichier ---
|
| 817 |
+
const importButton = document.getElementById('import-button');
|
| 818 |
+
const fileInput = document.getElementById('file-input');
|
| 819 |
+
|
| 820 |
+
importButton.addEventListener('click', () => {
|
| 821 |
+
fileInput.click(); // Simuler le clic sur l'input file caché
|
| 822 |
+
});
|
| 823 |
+
|
| 824 |
+
fileInput.addEventListener('change', (event) => {
|
| 825 |
+
const file = event.target.files[0];
|
| 826 |
+
if (file) {
|
| 827 |
+
const reader = new FileReader();
|
| 828 |
+
reader.onload = (e) => {
|
| 829 |
+
const content = e.target.result;
|
| 830 |
+
// Créer le nouveau fichier avec le nom et le contenu du fichier importé
|
| 831 |
+
createNewFile(file.name, content);
|
| 832 |
+
};
|
| 833 |
+
reader.readAsText(file); // Lire le fichier en tant que texte
|
| 834 |
+
}
|
| 835 |
+
// Réinitialiser l'input file pour permettre l'importation du même fichier à nouveau
|
| 836 |
+
fileInput.value = null;
|
| 837 |
+
});
|
| 838 |
+
|
| 839 |
+
|
| 840 |
+
// 3. Événements et initialisation
|
| 841 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 842 |
+
// Initialiser CodeMirror avec le fichier actif par défaut
|
| 843 |
+
const activeFile = files.find(f => f.isActive);
|
| 844 |
+
if (activeFile) {
|
| 845 |
+
initializeEditor(activeFile.content, activeFile.mode);
|
| 846 |
+
}
|
| 847 |
+
|
| 848 |
+
// Événement factice pour le bouton Sauvegarder
|
| 849 |
+
document.getElementById('save-button').addEventListener('click', () => {
|
| 850 |
+
const active = files.find(f => f.isActive);
|
| 851 |
+
alert(`Fichier "${active.name}" sauvegardé localement!\nContenu: ${active.content.substring(0, 50)}...`);
|
| 852 |
+
});
|
| 853 |
+
|
| 854 |
+
// Rendu initial des onglets et de l'explorateur
|
| 855 |
+
renderTabs();
|
| 856 |
+
renderFileExplorer();
|
| 857 |
+
});
|
| 858 |
+
</script>
|
| 859 |
+
</body>
|
| 860 |
+
</html>
|
templates/dashboard.html
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Mailix | Tableau de Bord - Pro</title>
|
| 7 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
/* Configuration de la police Inter */
|
| 13 |
+
body { font-family: 'Inter', sans-serif; }
|
| 14 |
+
|
| 15 |
+
/* Transition pour un effet doux des couleurs */
|
| 16 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 17 |
+
|
| 18 |
+
/* Style et positionnement du bouton de Thème */
|
| 19 |
+
.theme-switch {
|
| 20 |
+
background: none;
|
| 21 |
+
border: none;
|
| 22 |
+
cursor: pointer;
|
| 23 |
+
font-size: 24px;
|
| 24 |
+
transition: color 0.2s;
|
| 25 |
+
position: fixed;
|
| 26 |
+
top: 1rem;
|
| 27 |
+
right: 1rem;
|
| 28 |
+
z-index: 60; /* Z-index plus élevé pour s'assurer qu'il est au-dessus de tout */
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Définir les Variables de Thème (inchangé) */
|
| 32 |
+
/* Mode Sombre (Défaut) */
|
| 33 |
+
:root, .dark {
|
| 34 |
+
--bg-page: #121212;
|
| 35 |
+
--bg-card: #1E1E1E;
|
| 36 |
+
--bg-sidebar: #1E1E1E;
|
| 37 |
+
--bg-sidebar-active: #2C2C2C;
|
| 38 |
+
--border-sidebar: #383838;
|
| 39 |
+
--text-color: #FFFFFF;
|
| 40 |
+
--text-secondary: #D1D5DB;
|
| 41 |
+
--text-link: #3B82F6;
|
| 42 |
+
--text-link-hover: #60A5FA;
|
| 43 |
+
--input-bg: #2C2C2C;
|
| 44 |
+
--input-border: #4B5563;
|
| 45 |
+
--input-text-key: #6EE7B7;
|
| 46 |
+
--primary-color: #3B82F6;
|
| 47 |
+
--primary-hover: #2563EB;
|
| 48 |
+
--warning-bg: #451A03;
|
| 49 |
+
--warning-border: #78350F;
|
| 50 |
+
--warning-text: #FBBF24;
|
| 51 |
+
}
|
| 52 |
+
/* Mode Clair */
|
| 53 |
+
.light {
|
| 54 |
+
--bg-page: #F5F5F5;
|
| 55 |
+
--bg-card: #FFFFFF;
|
| 56 |
+
--bg-sidebar: #FFFFFF;
|
| 57 |
+
--bg-sidebar-active: #F3F4F6;
|
| 58 |
+
--border-sidebar: #D1D5DB;
|
| 59 |
+
--text-color: #000000;
|
| 60 |
+
--text-secondary: #4B5563;
|
| 61 |
+
--text-link: #1D4ED8;
|
| 62 |
+
--text-link-hover: #3B82F6;
|
| 63 |
+
--input-bg: #FFFFFF;
|
| 64 |
+
--input-border: #D1D5DB;
|
| 65 |
+
--input-text-key: #059669;
|
| 66 |
+
--primary-color: #3B82F6;
|
| 67 |
+
--primary-hover: #2563EB;
|
| 68 |
+
--warning-bg: #FEF3C7;
|
| 69 |
+
--warning-border: #FBBF24;
|
| 70 |
+
--warning-text: #92400E;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
/* Appliquer les variables au body et aux éléments (inchangé) */
|
| 74 |
+
.bg-page-var { background-color: var(--bg-page); }
|
| 75 |
+
.bg-card-var { background-color: var(--bg-card); }
|
| 76 |
+
.bg-sidebar-var { background-color: var(--bg-sidebar); }
|
| 77 |
+
.border-sidebar-var { border-color: var(--border-sidebar); }
|
| 78 |
+
.text-color-var { color: var(--text-color); }
|
| 79 |
+
.text-secondary-var { color: var(--text-secondary); }
|
| 80 |
+
.text-link-var { color: var(--text-link); }
|
| 81 |
+
.hover\:text-link-hover-var:hover { color: var(--text-link-hover); }
|
| 82 |
+
.bg-input-var { background-color: var(--input-bg); }
|
| 83 |
+
.border-input-var { border-color: var(--input-border); }
|
| 84 |
+
.text-input-key-var { color: var(--input-text-key); }
|
| 85 |
+
.bg-primary-color-var { background-color: var(--primary-color); }
|
| 86 |
+
.hover\:bg-primary-hover-var:hover { background-color: var(--primary-hover); }
|
| 87 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color); }
|
| 88 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color); }
|
| 89 |
+
.bg-sidebar-active-var { background-color: var(--bg-sidebar-active); }
|
| 90 |
+
.bg-warning-var { background-color: var(--warning-bg); }
|
| 91 |
+
.border-warning-var { border-color: var(--warning-border); }
|
| 92 |
+
.text-warning-var { color: var(--warning-text); }
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
/* Styles pour les sidebars - FIXES */
|
| 96 |
+
.sidebar {
|
| 97 |
+
transition: transform 0.3s ease-in-out;
|
| 98 |
+
position: fixed;
|
| 99 |
+
top: 0;
|
| 100 |
+
z-index: 30;
|
| 101 |
+
height: 100vh;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
/* Sidebar Gauche */
|
| 105 |
+
.sidebar-left {
|
| 106 |
+
transform: translateX(-100%); /* Masqué par défaut sur mobile */
|
| 107 |
+
left: 0;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
.sidebar-left.open {
|
| 111 |
+
transform: translateX(0);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/* Sidebar Droite */
|
| 115 |
+
.sidebar-right {
|
| 116 |
+
transform: translateX(100%); /* Masqué par défaut sur mobile */
|
| 117 |
+
right: 0;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
.sidebar-right.open {
|
| 121 |
+
transform: translateX(0);
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
/* Sur les grands écrans (lg), les sidebars sont statiques et toujours visibles */
|
| 125 |
+
@media (min-width: 1024px) {
|
| 126 |
+
.sidebar {
|
| 127 |
+
transform: translateX(0) !important;
|
| 128 |
+
height: 100vh;
|
| 129 |
+
}
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/* Conteneur principal pour décaler le contenu sur les grands écrans (lg) */
|
| 133 |
+
/* La marge doit correspondre à la largeur des sidebars (w-64 = 256px) */
|
| 134 |
+
@media (min-width: 1024px) {
|
| 135 |
+
.main-content {
|
| 136 |
+
margin-left: 256px; /* Marge Gauche pour la sidebar-left */
|
| 137 |
+
margin-right: 256px; /* Marge Droite pour la sidebar-right */
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
/* Ajustement du bouton de Thème pour ne pas interférer avec la sidebar droite sur mobile */
|
| 142 |
+
@media (max-width: 1023px) {
|
| 143 |
+
.theme-switch {
|
| 144 |
+
right: 5rem; /* Déplacé à gauche pour ne pas être sous le bouton de menu (sidebar droite) */
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
/* Style pour les boutons de toggle sur mobile */
|
| 149 |
+
.mobile-toggle-button {
|
| 150 |
+
z-index: 40; /* Au-dessus de la sidebar mais sous le theme-switch */
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
</style>
|
| 154 |
+
</head>
|
| 155 |
+
|
| 156 |
+
<body class="bg-page-var text-color-var min-h-screen transition-colors-theme">
|
| 157 |
+
|
| 158 |
+
<button id="theme-toggle" class="theme-switch text-color-var hover:text-link-hover-var transition-colors-theme">
|
| 159 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 160 |
+
</button>
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
<aside id="sidebar-left" class="sidebar sidebar-left w-64 bg-sidebar-var border-r border-sidebar-var p-6 flex flex-col transition-colors-theme">
|
| 164 |
+
|
| 165 |
+
<div class="flex items-center mb-6 shrink-0">
|
| 166 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 167 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Mailix</span>
|
| 168 |
+
</div>
|
| 169 |
+
|
| 170 |
+
<div class="flex-grow overflow-y-auto pr-2" id="scrollable-nav-container">
|
| 171 |
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-secondary-var mb-2">Fichiers Ouverts</h3>
|
| 172 |
+
<nav id="file-explorer" class="space-y-1 pb-4 border-b border-sidebar-var/50 mb-4">
|
| 173 |
+
</nav>
|
| 174 |
+
|
| 175 |
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-secondary-var mb-2">Navigation</h3>
|
| 176 |
+
<nav class="space-y-3 pb-4">
|
| 177 |
+
<a href="{{ url_for('user_bp.dashboard') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 178 |
+
<span class="material-symbols-rounded">dashboard</span>
|
| 179 |
+
<span class="ml-3">Dashboard</span>
|
| 180 |
+
</a>
|
| 181 |
+
|
| 182 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 183 |
+
<span class="material-symbols-rounded">person</span>
|
| 184 |
+
<span class="ml-3">Profil</span>
|
| 185 |
+
</a>
|
| 186 |
+
|
| 187 |
+
<a href="/aide" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 188 |
+
<span class="material-symbols-rounded">help</span>
|
| 189 |
+
<span class="ml-3">Aide & Support</span>
|
| 190 |
+
</a>
|
| 191 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 192 |
+
<span class="material-symbols-rounded">person</span>
|
| 193 |
+
<span class="ml-3">Profil</span>
|
| 194 |
+
</a>
|
| 195 |
+
|
| 196 |
+
<a href="/tarifs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 197 |
+
<span class="material-symbols-rounded">payments</span>
|
| 198 |
+
<span class="ml-3">Tarifs</span>
|
| 199 |
+
</a>
|
| 200 |
+
<a href="/statut" class="flex items-center p-3 bg-sidebar-active-var text-color-var rounded-lg transition duration-150 transition-colors-theme">
|
| 201 |
+
<span class="material-symbols-rounded">monitor_heart</span>
|
| 202 |
+
<span class="ml-3">Statut de l'API</span>
|
| 203 |
+
</a>
|
| 204 |
+
<a href="{{ url_for('user_bp.deconnexion') }}" id="logout-button-sidebar" class="flex items-center p-3 text-red-500 hover:text-red-400 hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 205 |
+
<span class="material-symbols-rounded">logout</span>
|
| 206 |
+
<span class="ml-3">Déconnexion</span>
|
| 207 |
+
</a>
|
| 208 |
+
</nav>
|
| 209 |
+
</div>
|
| 210 |
+
|
| 211 |
+
<div class="mt-auto pt-4 text-xs text-secondary-var transition-colors-theme border-t border-sidebar-var/50 shrink-0">
|
| 212 |
+
<p>Connecté en tant que: <span class="font-semibold text-color-var transition-colors-theme">{{ user.email if user and user.email else 'Chargement...' }}</span></p>
|
| 213 |
+
<p>Plan: <span class="font-semibold text-color-var transition-colors-theme">{{ (user.plan | upper) if user and user.plan else 'GRATUIT' }}</span></p>
|
| 214 |
+
</div>
|
| 215 |
+
|
| 216 |
+
</aside>
|
| 217 |
+
|
| 218 |
+
<aside id="sidebar-right" class="sidebar sidebar-right w-64 bg-sidebar-var border-l border-sidebar-var p-6 lg:block transition-colors-theme">
|
| 219 |
+
|
| 220 |
+
<a href="/nouveau_project" id="new-project-button" class="flex items-center justify-center w-full p-3 mb-6 bg-primary-color-var hover:bg-primary-hover-var text-white font-semibold rounded-lg shadow-md transition duration-150">
|
| 221 |
+
<span class="material-symbols-rounded mr-2">add</span> Créer un Projet
|
| 222 |
+
</a>
|
| 223 |
+
|
| 224 |
+
<h3 class="text-lg font-semibold mb-4 text-color-var transition-colors-theme">Outils</h3>
|
| 225 |
+
<nav class="space-y-3">
|
| 226 |
+
|
| 227 |
+
<a href="/parametres" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 228 |
+
<span class="material-symbols-rounded">settings</span> <span class="ml-3">Paramètres</span>
|
| 229 |
+
</a>
|
| 230 |
+
|
| 231 |
+
<a href="/aide" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 232 |
+
<span class="material-symbols-rounded">help</span>
|
| 233 |
+
<span class="ml-3">Aide & Support</span>
|
| 234 |
+
</a>
|
| 235 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 236 |
+
<span class="material-symbols-rounded">person</span>
|
| 237 |
+
<span class="ml-3">Profil</span>
|
| 238 |
+
</a>
|
| 239 |
+
|
| 240 |
+
<a href="/tarifs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 241 |
+
<span class="material-symbols-rounded">payments</span>
|
| 242 |
+
<span class="ml-3">Tarifs</span>
|
| 243 |
+
</a>
|
| 244 |
+
|
| 245 |
+
</nav>
|
| 246 |
+
|
| 247 |
+
<div class="absolute bottom-6 w-52 text-xs text-secondary-var transition-colors-theme">
|
| 248 |
+
<p class="font-semibold text-color-var transition-colors-theme mb-1">Espace de travail</p>
|
| 249 |
+
<ul class="space-y-1">
|
| 250 |
+
<li><a href="#" class="text-link-var hover:text-link-hover-var">Mailix Corp (Actif)</a></li>
|
| 251 |
+
<li><a href="#" class="text-link-var hover:text-link-hover-var">Mon Sandbox</a></li>
|
| 252 |
+
</ul>
|
| 253 |
+
</div>
|
| 254 |
+
|
| 255 |
+
</aside>
|
| 256 |
+
|
| 257 |
+
<div id="main-content" class="main-content p-8 transition-colors-theme">
|
| 258 |
+
|
| 259 |
+
<header class="lg:hidden flex justify-between items-center mb-8">
|
| 260 |
+
<button id="sidebar-left-toggle" class="mobile-toggle-button p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme">
|
| 261 |
+
<span class="material-symbols-rounded text-color-var">menu</span>
|
| 262 |
+
</button>
|
| 263 |
+
<div class="flex items-center">
|
| 264 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 265 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Mailix</span>
|
| 266 |
+
</div>
|
| 267 |
+
<button id="sidebar-right-toggle" class="mobile-toggle-button p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme">
|
| 268 |
+
<span class="material-symbols-rounded text-color-var">settings</span> </button>
|
| 269 |
+
</header>
|
| 270 |
+
|
| 271 |
+
<h1 class="text-3xl font-bold mb-8 text-color-var transition-colors-theme">Tableau de Bord Principal 📊</h1>
|
| 272 |
+
|
| 273 |
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12">
|
| 274 |
+
|
| 275 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme">
|
| 276 |
+
<div class="flex items-center justify-between">
|
| 277 |
+
<span class="material-symbols-rounded text-3xl text-primary-color-var">cloud_upload</span>
|
| 278 |
+
<p class="text-2xl font-bold text-color-var">12,450</p>
|
| 279 |
+
</div>
|
| 280 |
+
<p class="text-sm text-secondary-var mt-2">Requêtes Totales</p>
|
| 281 |
+
</div>
|
| 282 |
+
|
| 283 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme">
|
| 284 |
+
<div class="flex items-center justify-between">
|
| 285 |
+
<span class="material-symbols-rounded text-3xl text-input-text-key-var">check_circle</span>
|
| 286 |
+
<p class="text-2xl font-bold text-color-var">99.8%</p>
|
| 287 |
+
</div>
|
| 288 |
+
<p class="text-sm text-secondary-var mt-2">Taux de Succès</p>
|
| 289 |
+
</div>
|
| 290 |
+
|
| 291 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme">
|
| 292 |
+
<div class="flex items-center justify-between">
|
| 293 |
+
<span class="material-symbols-rounded text-3xl text-link-hover-var">wallet</span>
|
| 294 |
+
<p class="text-2xl font-bold text-color-var">150$</p>
|
| 295 |
+
</div>
|
| 296 |
+
<p class="text-sm text-secondary-var mt-2">Coût Estimé (Mois)</p>
|
| 297 |
+
</div>
|
| 298 |
+
|
| 299 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme">
|
| 300 |
+
<div class="flex items-center justify-between">
|
| 301 |
+
<span class="material-symbols-rounded text-3xl text-warning-text-var">person_add</span>
|
| 302 |
+
<p class="text-2xl font-bold text-color-var">482</p>
|
| 303 |
+
</div>
|
| 304 |
+
<p class="text-sm text-secondary-var mt-2">Utilisateurs Uniques</p>
|
| 305 |
+
</div>
|
| 306 |
+
|
| 307 |
+
</div>
|
| 308 |
+
|
| 309 |
+
<h2 class="text-2xl font-bold mb-6 text-color-var transition-colors-theme">Mes Projets Récents</h2>
|
| 310 |
+
|
| 311 |
+
<div class="space-y-6">
|
| 312 |
+
|
| 313 |
+
<div class="bg-card-var p-6 rounded-lg shadow-lg border border-sidebar-var transition-colors-theme flex justify-between items-start">
|
| 314 |
+
<div>
|
| 315 |
+
<h3 class="text-xl font-semibold text-color-var transition-colors-theme mb-2">Projet: API de Traduction (V3)</h3>
|
| 316 |
+
<p class="text-secondary-var text-sm mb-3">Dernière modification: 15 minutes ago</p>
|
| 317 |
+
<div class="flex items-center space-x-3 text-sm">
|
| 318 |
+
<span class="text-input-key-var font-medium flex items-center">
|
| 319 |
+
<span class="material-symbols-rounded text-lg mr-1">public</span> Public
|
| 320 |
+
</span>
|
| 321 |
+
<span class="text-secondary-var flex items-center">
|
| 322 |
+
<span class="material-symbols-rounded text-lg mr-1">code</span> Type: Snippet de Code (Python)
|
| 323 |
+
</span>
|
| 324 |
+
</div>
|
| 325 |
+
</div>
|
| 326 |
+
<a href="/project/api-translation-v3" class="text-link-var hover:text-link-hover-var font-medium flex items-center p-2 rounded-lg hover:bg-sidebar-active-var transition-colors-theme">
|
| 327 |
+
Ouvrir l'éditeur
|
| 328 |
+
<span class="material-symbols-rounded ml-1">arrow_forward</span>
|
| 329 |
+
</a>
|
| 330 |
+
</div>
|
| 331 |
+
|
| 332 |
+
<div class="bg-card-var p-6 rounded-lg shadow-lg border border-sidebar-var transition-colors-theme flex justify-between items-start">
|
| 333 |
+
<div>
|
| 334 |
+
<h3 class="text-xl font-semibold text-color-var transition-colors-theme mb-2">Micro-App: Calculatrice de Taux</h3>
|
| 335 |
+
<p class="text-secondary-var text-sm mb-3">Dernière modification: Hier</p>
|
| 336 |
+
<div class="flex items-center space-x-3 text-sm">
|
| 337 |
+
<span class="text-warning-text-var font-medium flex items-center">
|
| 338 |
+
<span class="material-symbols-rounded text-lg mr-1">lock</span> Privé
|
| 339 |
+
</span>
|
| 340 |
+
<span class="text-secondary-var flex items-center">
|
| 341 |
+
<span class="material-symbols-rounded text-lg mr-1">web_asset</span> Type: Micro-Application Web (HTML/JS)
|
| 342 |
+
</span>
|
| 343 |
+
</div>
|
| 344 |
+
</div>
|
| 345 |
+
<a href="/project/rate-calculator" class="text-link-var hover:text-link-hover-var font-medium flex items-center p-2 rounded-lg hover:bg-sidebar-active-var transition-colors-theme">
|
| 346 |
+
Ouvrir l'éditeur
|
| 347 |
+
<span class="material-symbols-rounded ml-1">arrow_forward</span>
|
| 348 |
+
</a>
|
| 349 |
+
</div>
|
| 350 |
+
|
| 351 |
+
<div class="lg:hidden text-center mt-8">
|
| 352 |
+
<a href="/nouveau_project" class="inline-flex items-center justify-center p-3 bg-primary-color-var hover:bg-primary-hover-var text-white font-semibold rounded-lg shadow-lg transition duration-150">
|
| 353 |
+
<span class="material-symbols-rounded mr-2">add</span>
|
| 354 |
+
Créer un Nouveau Projet
|
| 355 |
+
</a>
|
| 356 |
+
</div>
|
| 357 |
+
|
| 358 |
+
</div>
|
| 359 |
+
|
| 360 |
+
<div class="mt-12">
|
| 361 |
+
<h2 class="text-xl font-semibold mb-4 text-color-var transition-colors-theme">Journal d'Activité Récente</h2>
|
| 362 |
+
<p class="text-secondary-var mb-6 transition-colors-theme">Les 5 dernières actions significatives sur votre compte.</p>
|
| 363 |
+
|
| 364 |
+
<ul class="space-y-3 bg-card-var p-4 rounded-lg shadow-xl border border-sidebar-var">
|
| 365 |
+
<li class="p-3 border-b border-sidebar-var flex justify-between items-center text-sm">
|
| 366 |
+
<span class="text-color-var font-medium">API: Endpoint /generation appelé</span>
|
| 367 |
+
<span class="text-secondary-var">2 minutes ago</span>
|
| 368 |
+
</li>
|
| 369 |
+
<li class="p-3 border-b border-sidebar-var flex justify-between items-center text-sm">
|
| 370 |
+
<span class="text-color-var font-medium">Connexion réussie (IP: 192.168.1.1)</span>
|
| 371 |
+
<span class="text-secondary-var">1 heure ago</span>
|
| 372 |
+
</li>
|
| 373 |
+
<li class="p-3 border-b border-sidebar-var flex justify-between items-center text-sm">
|
| 374 |
+
<span class="text-color-var font-medium">API: Erreur de quota /analyse</span>
|
| 375 |
+
<span class="text-secondary-var text-red-400">3 heures ago</span>
|
| 376 |
+
</li>
|
| 377 |
+
<li class="p-3 border-b border-sidebar-var flex justify-between items-center text-sm">
|
| 378 |
+
<span class="text-color-var font-medium">Mise à jour du profil (Nom)</span>
|
| 379 |
+
<span class="text-secondary-var">Hier</span>
|
| 380 |
+
</li>
|
| 381 |
+
<li class="p-3 flex justify-between items-center text-sm">
|
| 382 |
+
<span class="text-color-var font-medium">API: Endpoint /translate appelé</span>
|
| 383 |
+
<span class="text-secondary-var">Il y a 2 jours</span>
|
| 384 |
+
</li>
|
| 385 |
+
</ul>
|
| 386 |
+
|
| 387 |
+
<div class="mt-4 text-right">
|
| 388 |
+
<a href="api_logs.html" class="text-sm text-link-var hover:text-link-hover-var font-medium transition-colors-theme">
|
| 389 |
+
Voir tous les logs →
|
| 390 |
+
</a>
|
| 391 |
+
</div>
|
| 392 |
+
</div>
|
| 393 |
+
|
| 394 |
+
</div>
|
| 395 |
+
|
| 396 |
+
<script>
|
| 397 |
+
// Logique du thème (inchangée)
|
| 398 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 399 |
+
const html = document.documentElement;
|
| 400 |
+
|
| 401 |
+
const updateIcon = () => {
|
| 402 |
+
const icon = themeToggle.querySelector('.material-symbols-rounded');
|
| 403 |
+
if (html.classList.contains('light')) {
|
| 404 |
+
icon.textContent = 'light_mode';
|
| 405 |
+
} else {
|
| 406 |
+
icon.textContent = 'dark_mode';
|
| 407 |
+
}
|
| 408 |
+
};
|
| 409 |
+
|
| 410 |
+
const savedTheme = localStorage.getItem('theme');
|
| 411 |
+
if (savedTheme === 'light') {
|
| 412 |
+
html.classList.remove('dark');
|
| 413 |
+
html.classList.add('light');
|
| 414 |
+
} else {
|
| 415 |
+
html.classList.add('dark');
|
| 416 |
+
html.classList.remove('light');
|
| 417 |
+
}
|
| 418 |
+
updateIcon();
|
| 419 |
+
|
| 420 |
+
themeToggle.addEventListener('click', () => {
|
| 421 |
+
if (html.classList.contains('dark')) {
|
| 422 |
+
html.classList.remove('dark');
|
| 423 |
+
html.classList.add('light');
|
| 424 |
+
localStorage.setItem('theme', 'light');
|
| 425 |
+
} else {
|
| 426 |
+
html.classList.remove('light');
|
| 427 |
+
html.classList.add('dark');
|
| 428 |
+
localStorage.setItem('theme', 'dark');
|
| 429 |
+
}
|
| 430 |
+
updateIcon();
|
| 431 |
+
});
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
// Logique pour la Sidebar Gauche sur mobile
|
| 435 |
+
const sidebarLeftToggle = document.getElementById('sidebar-left-toggle');
|
| 436 |
+
const sidebarLeft = document.getElementById('sidebar-left');
|
| 437 |
+
|
| 438 |
+
sidebarLeftToggle.addEventListener('click', () => {
|
| 439 |
+
sidebarLeft.classList.toggle('open');
|
| 440 |
+
// Fermer l'autre sidebar si elle est ouverte pour éviter le chevauchement
|
| 441 |
+
sidebarRight.classList.remove('open');
|
| 442 |
+
});
|
| 443 |
+
|
| 444 |
+
// Logique pour la Sidebar Droite sur mobile
|
| 445 |
+
const sidebarRightToggle = document.getElementById('sidebar-right-toggle');
|
| 446 |
+
const sidebarRight = document.getElementById('sidebar-right');
|
| 447 |
+
|
| 448 |
+
sidebarRightToggle.addEventListener('click', () => {
|
| 449 |
+
sidebarRight.classList.toggle('open');
|
| 450 |
+
// Fermer l'autre sidebar si elle est ouverte
|
| 451 |
+
sidebarLeft.classList.remove('open');
|
| 452 |
+
});
|
| 453 |
+
|
| 454 |
+
// Logique de Déconnexion (Conservée)
|
| 455 |
+
const logoutHandler = async (e) => {
|
| 456 |
+
e.preventDefault();
|
| 457 |
+
// Simulation de la redirection pour la déconnexion
|
| 458 |
+
window.location.href = document.getElementById('logout-button-sidebar').href;
|
| 459 |
+
};
|
| 460 |
+
// On attache l'événement à la déconnexion dans la sidebar.
|
| 461 |
+
document.getElementById('logout-button-sidebar').addEventListener('click', logoutHandler);
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
</script>
|
| 465 |
+
</body>
|
| 466 |
+
</html>
|
templates/documentation.html
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Documentation API - Nexus</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
|
| 9 |
+
<style>
|
| 10 |
+
body { font-family: 'Inter', sans-serif; }
|
| 11 |
+
.code-block {
|
| 12 |
+
background-color: #1f2937; /* gray-800 */
|
| 13 |
+
border: 1px solid #3b82f6; /* blue-500 */
|
| 14 |
+
padding: 1rem;
|
| 15 |
+
/* Suppression des bords arrondis pour un look carré */
|
| 16 |
+
overflow-x: auto;
|
| 17 |
+
margin-top: 0.75rem;
|
| 18 |
+
}
|
| 19 |
+
</style>
|
| 20 |
+
</head>
|
| 21 |
+
<body class="bg-gray-900 text-white min-h-screen">
|
| 22 |
+
|
| 23 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-6xl">
|
| 24 |
+
|
| 25 |
+
<header class="flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8">
|
| 26 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 27 |
+
NEXUS
|
| 28 |
+
</a>
|
| 29 |
+
<nav class="flex items-center space-x-4">
|
| 30 |
+
<a href="/tarifs" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 31 |
+
Tarifs
|
| 32 |
+
</a>
|
| 33 |
+
<a href="/a-propos" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 34 |
+
À Propos
|
| 35 |
+
</a>
|
| 36 |
+
{% if is_logged_in %}
|
| 37 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 38 |
+
Dashboard
|
| 39 |
+
</a>
|
| 40 |
+
{% else %}
|
| 41 |
+
<a href="/connexion" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 42 |
+
Connexion
|
| 43 |
+
</a>
|
| 44 |
+
{% endif %}
|
| 45 |
+
</nav>
|
| 46 |
+
</header>
|
| 47 |
+
|
| 48 |
+
<main class="space-y-16">
|
| 49 |
+
|
| 50 |
+
<section class="text-center p-8 bg-gray-800/50 shadow-lg border border-gray-700">
|
| 51 |
+
<h1 class="text-5xl font-extrabold text-white mb-4 leading-tight">
|
| 52 |
+
Documentation de l'API Nexus
|
| 53 |
+
</h1>
|
| 54 |
+
<p class="text-xl text-gray-300 max-w-4xl mx-auto">
|
| 55 |
+
Le guide complet pour intégrer l'authentification et la gestion utilisateur la plus sécurisée du marché dans vos applications, quel que soit votre langage.
|
| 56 |
+
</p>
|
| 57 |
+
</section>
|
| 58 |
+
|
| 59 |
+
<section class="space-y-6">
|
| 60 |
+
<h2 class="text-4xl font-extrabold text-blue-500 border-b-2 border-gray-700 pb-3">
|
| 61 |
+
1. Vue d'Ensemble & Clés API
|
| 62 |
+
</h2>
|
| 63 |
+
<p class="text-gray-300">
|
| 64 |
+
L'API Nexus est structurée autour d'une ressource unique pour l'authentification. Tous les appels nécessitent votre **Clé API** (`X-API-KEY`) pour l'identification de votre application, et un **Token JWT** pour les actions utilisateur spécifiques.
|
| 65 |
+
</p>
|
| 66 |
+
|
| 67 |
+
<div class="grid md:grid-cols-2 gap-6">
|
| 68 |
+
<div class="p-4 bg-gray-800 border-l-4 border-teal-500 shadow-md">
|
| 69 |
+
<h3 class="text-xl font-semibold text-teal-400 mb-2">Endpoint de Base :</h3>
|
| 70 |
+
<p class="font-mono text-sm code-block p-2 border-none">
|
| 71 |
+
<code class="text-gray-100">https://api.nexus-pro.com/v1/auth</code>
|
| 72 |
+
</p>
|
| 73 |
+
<p class="text-xs text-gray-400 mt-2">Ce chemin est la base de toutes les opérations d'authentification.</p>
|
| 74 |
+
</div>
|
| 75 |
+
<div class="p-4 bg-gray-800 border-l-4 border-yellow-500 shadow-md">
|
| 76 |
+
<h3 class="text-xl font-semibold text-yellow-400 mb-2">Clé API (Sécurité) :</h3>
|
| 77 |
+
<p class="font-mono text-sm code-block p-2 border-none">
|
| 78 |
+
<code class="text-gray-100">X-API-KEY: VOTRE_CLE_API_SECRETE</code>
|
| 79 |
+
</p>
|
| 80 |
+
<p class="text-xs text-gray-400 mt-2">À inclure dans l'entête de chaque requête (sauf mention contraire).</p>
|
| 81 |
+
</div>
|
| 82 |
+
</div>
|
| 83 |
+
</section>
|
| 84 |
+
|
| 85 |
+
<section class="space-y-8">
|
| 86 |
+
<h2 class="text-4xl font-extrabold text-blue-500 border-b-2 border-gray-700 pb-3">
|
| 87 |
+
2. Flux d'Authentification
|
| 88 |
+
</h2>
|
| 89 |
+
|
| 90 |
+
<h3 class="text-2xl font-semibold text-white border-b border-gray-800 pb-1">
|
| 91 |
+
2.1 S'inscrire (POST /register)
|
| 92 |
+
</h3>
|
| 93 |
+
<p class="text-gray-300">
|
| 94 |
+
Crée un nouvel utilisateur. Le système retourne le token JWT si l'inscription est réussie.
|
| 95 |
+
</p>
|
| 96 |
+
<div class="grid md:grid-cols-2 gap-8">
|
| 97 |
+
<div>
|
| 98 |
+
<p class="text-lg font-bold text-teal-400 mb-2">cURL (Exemple Rapide)</p>
|
| 99 |
+
<pre class="code-block"><code class="language-bash">curl -X POST "https://api.nexus-pro.com/v1/auth/register" \
|
| 100 |
+
-H "X-API-KEY: VOTRE_CLE_API_SECRETE" \
|
| 101 |
+
-H "Content-Type: application/json" \
|
| 102 |
+
-d '{
|
| 103 |
+
"email": "utilisateur@exemple.com",
|
| 104 |
+
"password": "motdepassefort123"
|
| 105 |
+
}'</code></pre>
|
| 106 |
+
</div>
|
| 107 |
+
<div>
|
| 108 |
+
<p class="text-lg font-bold text-teal-400 mb-2">Python (`requests`)</p>
|
| 109 |
+
<pre class="code-block"><code class="language-python">import requests
|
| 110 |
+
import json
|
| 111 |
+
url = "https://api.nexus-pro.com/v1/auth/register"
|
| 112 |
+
headers = {
|
| 113 |
+
"X-API-KEY": "VOTRE_CLE_API_SECRETE",
|
| 114 |
+
"Content-Type": "application/json"
|
| 115 |
+
}
|
| 116 |
+
payload = {"email": "user@example.com", "password": "strongpassword123"}
|
| 117 |
+
response = requests.post(url, headers=headers, json=payload)
|
| 118 |
+
print(response.json())</code></pre>
|
| 119 |
+
</div>
|
| 120 |
+
<div class="md:col-span-2">
|
| 121 |
+
<p class="text-lg font-bold text-teal-400 mb-2">JavaScript (Fetch)</p>
|
| 122 |
+
<pre class="code-block"><code class="language-javascript">const url = 'https://api.nexus-pro.com/v1/auth/register';
|
| 123 |
+
const response = await fetch(url, {
|
| 124 |
+
method: 'POST',
|
| 125 |
+
headers: {
|
| 126 |
+
'X-API-KEY': 'VOTRE_CLE_API_SECRETE',
|
| 127 |
+
'Content-Type': 'application/json'
|
| 128 |
+
},
|
| 129 |
+
body: JSON.stringify({
|
| 130 |
+
email: 'user@example.com',
|
| 131 |
+
password: 'strongpassword123'
|
| 132 |
+
})
|
| 133 |
+
});
|
| 134 |
+
const data = await response.json();
|
| 135 |
+
console.log(data);</code></pre>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<h3 class="text-2xl font-semibold text-white border-b border-gray-800 pb-1 pt-6">
|
| 140 |
+
2.2 Se connecter (POST /login)
|
| 141 |
+
</h3>
|
| 142 |
+
<p class="text-gray-300">
|
| 143 |
+
Authentifie un utilisateur existant. La réponse contient le **Token JWT** pour les requêtes futures.
|
| 144 |
+
</p>
|
| 145 |
+
<div class="grid md:grid-cols-2 gap-8">
|
| 146 |
+
<div>
|
| 147 |
+
<p class="text-lg font-bold text-teal-400 mb-2">cURL</p>
|
| 148 |
+
<pre class="code-block"><code class="language-bash">curl -X POST "https://api.nexus-pro.com/v1/auth/login" \
|
| 149 |
+
-H "X-API-KEY: VOTRE_CLE_API_SECRETE" \
|
| 150 |
+
-H "Content-Type: application/json" \
|
| 151 |
+
-d '{
|
| 152 |
+
"email": "utilisateur@exemple.com",
|
| 153 |
+
"password": "motdepassefort123"
|
| 154 |
+
}'</code></pre>
|
| 155 |
+
</div>
|
| 156 |
+
<div>
|
| 157 |
+
<p class="text-lg font-bold text-teal-400 mb-2">Python (`requests`)</p>
|
| 158 |
+
<pre class="code-block"><code class="language-python">import requests
|
| 159 |
+
url = "https://api.nexus-pro.com/v1/auth/login"
|
| 160 |
+
headers = {
|
| 161 |
+
"X-API-KEY": "VOTRE_CLE_API_SECRETE",
|
| 162 |
+
"Content-Type": "application/json"
|
| 163 |
+
}
|
| 164 |
+
payload = {"email": "user@example.com", "password": "strongpassword123"}
|
| 165 |
+
response = requests.post(url, headers=headers, json=payload)
|
| 166 |
+
token = response.json().get('jwt_token')
|
| 167 |
+
print(f"Token: {token}")</code></pre>
|
| 168 |
+
</div>
|
| 169 |
+
</div>
|
| 170 |
+
</section>
|
| 171 |
+
|
| 172 |
+
<section class="space-y-8">
|
| 173 |
+
<h2 class="text-4xl font-extrabold text-blue-500 border-b-2 border-gray-700 pb-3">
|
| 174 |
+
3. Gestion des Données Utilisateur (Token Requis)
|
| 175 |
+
</h2>
|
| 176 |
+
<p class="text-gray-300">
|
| 177 |
+
Toutes les requêtes de cette section doivent inclure l'entête <strong class="text-yellow-400">`Authorization: Bearer VOTRE_TOKEN_JWT`</strong> obtenu lors de la connexion.
|
| 178 |
+
</p>
|
| 179 |
+
|
| 180 |
+
<h3 class="text-2xl font-semibold text-white border-b border-gray-800 pb-1">
|
| 181 |
+
3.1 Récupérer les Informations Utilisateur (GET /user)
|
| 182 |
+
</h3>
|
| 183 |
+
<p class="text-gray-300">
|
| 184 |
+
Récupère le profil de l'utilisateur associé au Token JWT fourni.
|
| 185 |
+
</p>
|
| 186 |
+
<div class="grid md:grid-cols-2 gap-8">
|
| 187 |
+
<div>
|
| 188 |
+
<p class="text-lg font-bold text-teal-400 mb-2">cURL</p>
|
| 189 |
+
<pre class="code-block"><code class="language-bash">curl -X GET "https://api.nexus-pro.com/v1/auth/user" \
|
| 190 |
+
-H "Authorization: Bearer VOTRE_TOKEN_JWT"</code></pre>
|
| 191 |
+
</div>
|
| 192 |
+
<div>
|
| 193 |
+
<p class="text-lg font-bold text-teal-400 mb-2">JavaScript (Fetch)</p>
|
| 194 |
+
<pre class="code-block"><code class="language-javascript">const url = 'https://api.nexus-pro.com/v1/auth/user';
|
| 195 |
+
const userToken = localStorage.getItem('nexus_jwt'); // Exemple de récupération
|
| 196 |
+
const response = await fetch(url, {
|
| 197 |
+
method: 'GET',
|
| 198 |
+
headers: { 'Authorization': `Bearer ${userToken}` }
|
| 199 |
+
});
|
| 200 |
+
const data = await response.json();
|
| 201 |
+
console.log(data);</code></pre>
|
| 202 |
+
</div>
|
| 203 |
+
</div>
|
| 204 |
+
|
| 205 |
+
<h3 class="text-2xl font-semibold text-white border-b border-gray-800 pb-1 pt-6">
|
| 206 |
+
3.2 Mettre à Jour les Informations (PUT /user/update)
|
| 207 |
+
</h3>
|
| 208 |
+
<p class="text-gray-300">
|
| 209 |
+
Permet de modifier les informations de l'utilisateur (nom, prénom, etc.). Seuls les champs fournis sont mis à jour.
|
| 210 |
+
</p>
|
| 211 |
+
<div class="grid md:grid-cols-2 gap-8">
|
| 212 |
+
<div>
|
| 213 |
+
<p class="text-lg font-bold text-teal-400 mb-2">cURL</p>
|
| 214 |
+
<pre class="code-block"><code class="language-bash">curl -X PUT "https://api.nexus-pro.com/v1/auth/user/update" \
|
| 215 |
+
-H "Authorization: Bearer VOTRE_TOKEN_JWT" \
|
| 216 |
+
-H "Content-Type: application/json" \
|
| 217 |
+
-d '{
|
| 218 |
+
"first_name": "Jean",
|
| 219 |
+
"last_name": "Dupont"
|
| 220 |
+
}'</code></pre>
|
| 221 |
+
</div>
|
| 222 |
+
<div>
|
| 223 |
+
<p class="text-lg font-bold text-teal-400 mb-2">Python (`requests`)</p>
|
| 224 |
+
<pre class="code-block"><code class="language-python">import requests
|
| 225 |
+
url = "https://api.nexus-pro.com/v1/auth/user/update"
|
| 226 |
+
token = "VOTRE_TOKEN_JWT"
|
| 227 |
+
headers = {
|
| 228 |
+
"Authorization": f"Bearer {token}",
|
| 229 |
+
"Content-Type": "application/json"
|
| 230 |
+
}
|
| 231 |
+
payload = {"first_name": "Jean", "last_name": "Dupont"}
|
| 232 |
+
response = requests.put(url, headers=headers, json=payload)
|
| 233 |
+
print(response.json())</code></pre>
|
| 234 |
+
</div>
|
| 235 |
+
</div>
|
| 236 |
+
</section>
|
| 237 |
+
|
| 238 |
+
<section class="space-y-6">
|
| 239 |
+
<h2 class="text-4xl font-extrabold text-blue-500 border-b-2 border-gray-700 pb-3">
|
| 240 |
+
4. Logs, Erreurs et Tarification
|
| 241 |
+
</h2>
|
| 242 |
+
<h3 class="text-2xl font-semibold text-white border-b border-gray-800 pb-1">
|
| 243 |
+
Gestion des Erreurs
|
| 244 |
+
</h3>
|
| 245 |
+
<p class="text-gray-300">
|
| 246 |
+
Toutes les erreurs API sont retournées avec un code d'état HTTP standard (4xx pour les erreurs clients, 5xx pour les erreurs serveurs). Le corps de la réponse contiendra une description JSON détaillée de l'erreur.
|
| 247 |
+
</p>
|
| 248 |
+
<div class="code-block bg-gray-800/80 p-4 border-l-4 border-red-500 text-sm">
|
| 249 |
+
<pre><code class="language-json">{
|
| 250 |
+
"error": true,
|
| 251 |
+
"status_code": 401,
|
| 252 |
+
"message": "Token JWT manquant ou invalide. Veuillez vous reconnecter."
|
| 253 |
+
}</code></pre>
|
| 254 |
+
</div>
|
| 255 |
+
|
| 256 |
+
<h3 class="text-2xl font-semibold text-white border-b border-gray-800 pb-1 pt-6">
|
| 257 |
+
Accès aux Logs Détaillés
|
| 258 |
+
</h3>
|
| 259 |
+
<p class="text-gray-300">
|
| 260 |
+
Les utilisateurs du **Plan Professionnel** et supérieur bénéficient d'un accès à l'endpoint `/api-logs` pour un historique complet des tentatives de connexion, des échecs d'authentification et des activités du compte. Cette fonctionnalité est essentielle pour le monitoring de sécurité.
|
| 261 |
+
</p>
|
| 262 |
+
<div class="mt-4">
|
| 263 |
+
<a href="/tarifs" class="px-6 py-3 bg-teal-600 text-white text-lg font-bold shadow-md hover:bg-teal-700 transition duration-300">
|
| 264 |
+
Voir les Détails des Plans
|
| 265 |
+
</a>
|
| 266 |
+
</div>
|
| 267 |
+
</section>
|
| 268 |
+
|
| 269 |
+
</main>
|
| 270 |
+
|
| 271 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 272 |
+
© 2024 Nexus. Documentation API.
|
| 273 |
+
</footer>
|
| 274 |
+
</div>
|
| 275 |
+
|
| 276 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
| 277 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>
|
| 278 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
|
| 279 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
|
| 280 |
+
<script>
|
| 281 |
+
// Active la coloration syntaxique après le chargement du DOM
|
| 282 |
+
hljs.highlightAll();
|
| 283 |
+
</script>
|
| 284 |
+
</body>
|
| 285 |
+
</html>
|
templates/index.html
ADDED
|
@@ -0,0 +1,992 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<html lang="fr">
|
| 2 |
+
<head>
|
| 3 |
+
<meta charset="UTF-8">
|
| 4 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 5 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 6 |
+
<title>Mailix | Validation d'Email en Temps Réel</title>
|
| 7 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 8 |
+
<link rel="stylesheet"
|
| 9 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 10 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 11 |
+
<style>
|
| 12 |
+
/* PHASE 1 : Configuration et Base du Style (Dark Mode Exclusif & Pro) */
|
| 13 |
+
/* Suppression de toute la logique du mode clair. */
|
| 14 |
+
:root {
|
| 15 |
+
--bg-body: #0A0A0A; /* Noir Profond */
|
| 16 |
+
--bg-card: #141414; /* Plus foncé que l'interface pour le contraste subtil */
|
| 17 |
+
--bg-section: #141414;
|
| 18 |
+
--bg-code: #141414;
|
| 19 |
+
--border-color: #4b5563; /* Gris très foncé pour les bordures */
|
| 20 |
+
--color-accent: #4ade80; /* Vert Vif */
|
| 21 |
+
--text-color: #ffffff;
|
| 22 |
+
--text-secondary: #d1d5db; /* gray-300 */
|
| 23 |
+
--text-muted: #9ca3af; /* gray-400 */
|
| 24 |
+
--text-blue: var(--color-accent); /* Remplacer le bleu par le vert accent partout */
|
| 25 |
+
--shadow-color: rgba(0, 0, 0, 0.5);
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/* Application des variables aux styles existants et aux nouveaux éléments */
|
| 29 |
+
body {
|
| 30 |
+
font-family: 'Inter', sans-serif;
|
| 31 |
+
background-color: var(--bg-body);
|
| 32 |
+
color: var(--text-color);
|
| 33 |
+
min-height: 100vh;
|
| 34 |
+
/* Suppression de la transition car le mode clair est supprimé */
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
/* Fix pour le header qui est maintenant sticky */
|
| 38 |
+
.header-border { border-color: var(--border-color); }
|
| 39 |
+
.bg-header { background-color: var(--bg-body); }
|
| 40 |
+
|
| 41 |
+
.code-block {
|
| 42 |
+
border: 1px solid var(--border-color);
|
| 43 |
+
overflow-x: auto;
|
| 44 |
+
background-color: var(--bg-code);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/* Suppression du style pour theme-switch (mode clair supprimé) */
|
| 48 |
+
|
| 49 |
+
/* Adaptation Tailwind pour les autres éléments */
|
| 50 |
+
.section-bg {
|
| 51 |
+
background-color: var(--bg-section);
|
| 52 |
+
border-color: var(--border-color);
|
| 53 |
+
box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -2px var(--shadow-color);
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
/* PHASE 1.3/4.1 : Cartes et Contraste (Border Subtile) */
|
| 57 |
+
.card-bg {
|
| 58 |
+
background-color: var(--bg-card);
|
| 59 |
+
border: 1px solid var(--border-color);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.text-blue-500-var { color: var(--text-blue); }
|
| 63 |
+
.text-gray-300-var { color: var(--text-secondary); }
|
| 64 |
+
.text-gray-400-var { color: var(--text-muted); }
|
| 65 |
+
|
| 66 |
+
/* Ajustements spécifiques pour les éléments non couverts par une classe personnalisée */
|
| 67 |
+
.tab-button { border-bottom-color: var(--border-color); }
|
| 68 |
+
/* Mise à jour de la couleur d'accent pour l'onglet actif */
|
| 69 |
+
.tab-button.border-blue-500 { border-bottom-color: var(--color-accent) !important; color: var(--color-accent) !important; background-color: var(--bg-code) !important; }
|
| 70 |
+
.tab-button.hover\:text-white:hover { color: var(--text-color) !important; }
|
| 71 |
+
.tab-button.hover\:bg-gray-800:hover { background-color: var(--bg-card) !important; }
|
| 72 |
+
|
| 73 |
+
/* Remplacement du bleu par le vert pour les boutons CTA */
|
| 74 |
+
.btn-primary {
|
| 75 |
+
background-color: var(--color-accent);
|
| 76 |
+
color: var(--bg-body) !important; /* Texte noir sur vert */
|
| 77 |
+
font-weight: bold;
|
| 78 |
+
box-shadow: 0 4px 6px -1px rgba(74, 222, 128, 0.3), 0 2px 4px -2px rgba(74, 222, 128, 0.3);
|
| 79 |
+
transition: background-color 0.2s;
|
| 80 |
+
}
|
| 81 |
+
.btn-primary:hover {
|
| 82 |
+
opacity: 0.9;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/* Remplacement de la classe bg-blue-900/40 par son équivalent en vert */
|
| 86 |
+
.bg-green-900\/40 {
|
| 87 |
+
background-color: rgba(74, 222, 128, 0.15); /* Couleur basée sur --color-accent avec transparence */
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/* NOUVELLE RÈGLE CSS : Défilement Infini des Témoignages (Accéléré) */
|
| 91 |
+
@keyframes scroll-rtl {
|
| 92 |
+
0% { transform: translateX(0); }
|
| 93 |
+
100% { transform: translateX(-50%); }
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
.testimonial-container {
|
| 97 |
+
overflow: hidden;
|
| 98 |
+
width: 100%;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.testimonials-track {
|
| 102 |
+
display: flex;
|
| 103 |
+
animation: scroll-rtl 25s linear infinite; /* ACCÉLÉRÉ: 40s à 25s */
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
.testimonials-track:hover {
|
| 107 |
+
animation-play-state: paused;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
/* PHASE 4.1 : Témoignages (Carte avec bordure fine et fond subtil - COINS CARRÉS) */
|
| 111 |
+
.testimonial-card {
|
| 112 |
+
flex-shrink: 0;
|
| 113 |
+
width: 300px;
|
| 114 |
+
margin-right: 1.5rem;
|
| 115 |
+
border: 1px solid var(--border-color);
|
| 116 |
+
box-shadow: 0 4px 6px -1px var(--shadow-color);
|
| 117 |
+
background-color: var(--bg-card);
|
| 118 |
+
/* Suppression de rounded-lg pour des coins carrés */
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
/* Style pour les FAQ (Menu Déroulant) */
|
| 122 |
+
.faq-item summary {
|
| 123 |
+
cursor: pointer;
|
| 124 |
+
list-style: none; /* Cache le marqueur par défaut */
|
| 125 |
+
display: flex;
|
| 126 |
+
justify-content: space-between;
|
| 127 |
+
align-items: center;
|
| 128 |
+
padding: 1rem 0;
|
| 129 |
+
font-weight: 600;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
.faq-item summary::-webkit-details-marker {
|
| 133 |
+
display: none; /* Cache le marqueur pour Chrome/Safari */
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
/* Rotation de l'icône FAQ */
|
| 137 |
+
.faq-icon {
|
| 138 |
+
transition: transform 0.2s ease;
|
| 139 |
+
}
|
| 140 |
+
.faq-item[open] .faq-icon {
|
| 141 |
+
transform: rotate(45deg); /* Tourne l'icône en croix */
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
/* CSS Spécifique au Carrousel de Logos */
|
| 145 |
+
@keyframes scroll-logos {
|
| 146 |
+
0% { transform: translateX(0); }
|
| 147 |
+
100% { transform: translateX(-50%); }
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
.logo-container {
|
| 151 |
+
overflow: hidden;
|
| 152 |
+
width: 100%;
|
| 153 |
+
padding: 2rem 0; /* Ajout d'un padding vertical pour l'esthétique */
|
| 154 |
+
background-color: var(--bg-card);
|
| 155 |
+
border: 1px solid var(--border-color);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.logos-track {
|
| 159 |
+
display: flex;
|
| 160 |
+
animation: scroll-logos 20s linear infinite; /* Défilement rapide */
|
| 161 |
+
width: max-content; /* S'assure que la piste est assez large */
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
.logos-track:hover {
|
| 165 |
+
animation-play-state: paused;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
.logo-item {
|
| 169 |
+
flex-shrink: 0;
|
| 170 |
+
width: 120px; /* Taille fixe pour le logo */
|
| 171 |
+
height: 120px;
|
| 172 |
+
margin: 0 1.5rem; /* Espace entre les logos */
|
| 173 |
+
display: flex;
|
| 174 |
+
align-items: center;
|
| 175 |
+
justify-content: center;
|
| 176 |
+
opacity: 0.9; /* Légèrement transparent pour le mode sombre */
|
| 177 |
+
transition: opacity 0.3s, transform 0.3s; /* Ajout de la transition de transformation */
|
| 178 |
+
}
|
| 179 |
+
.logo-item:hover {
|
| 180 |
+
opacity: 1;
|
| 181 |
+
transform: scale(1.05); /* Petit zoom au survol pour un effet professionnel */
|
| 182 |
+
}
|
| 183 |
+
.logo-item img {
|
| 184 |
+
max-width: 100%;
|
| 185 |
+
max-height: 80px; /* Taille du logo en gros */
|
| 186 |
+
/* REMOVE FILTER: Le filtre a été retiré pour afficher les logos en couleur */
|
| 187 |
+
}
|
| 188 |
+
</style>
|
| 189 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
|
| 190 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
| 191 |
+
</head>
|
| 192 |
+
<body>
|
| 193 |
+
|
| 194 |
+
<header class="fixed top-0 left-0 right-0 z-50 flex justify-center py-3 border-b header-border bg-header shadow-xl transition-colors duration-300">
|
| 195 |
+
<div class="container mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 flex flex-col sm:flex-row justify-between items-center w-full">
|
| 196 |
+
<a href="/" class="text-4xl font-extrabold text-green-500 tracking-wider mb-2 sm:mb-0">
|
| 197 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Mailix Logo" class="h-8 w-auto">
|
| 198 |
+
</a>
|
| 199 |
+
<nav class="flex items-center space-x-2 sm:space-x-4">
|
| 200 |
+
|
| 201 |
+
<a href="/documentation" class="px-2 py-1 sm:px-4 sm:py-2 text-color hover:text-blue-500-var transition duration-200 font-medium text-sm sm:text-base">
|
| 202 |
+
Docs
|
| 203 |
+
</a>
|
| 204 |
+
<a href="/tarifs" class="px-2 py-1 sm:px-4 sm:py-2 text-color hover:text-blue-500-var transition duration-200 font-medium text-sm sm:text-base">
|
| 205 |
+
Tarifs
|
| 206 |
+
</a>
|
| 207 |
+
<a href="/a-propos" class="px-2 py-1 sm:px-4 sm:py-2 text-color hover:text-blue-500-var transition duration-200 font-medium text-sm sm:text-base hidden md:block">
|
| 208 |
+
Enterprise
|
| 209 |
+
</a>
|
| 210 |
+
<a href="/support" class="px-2 py-1 sm:px-4 sm:py-2 text-color hover:text-blue-500-var transition duration-200 font-medium text-sm sm:text-base hidden sm:block">
|
| 211 |
+
Support
|
| 212 |
+
</a>
|
| 213 |
+
|
| 214 |
+
<a href="/connexion" class="px-3 py-1 sm:px-4 sm:py-2 text-white btn-primary transition duration-200 text-sm sm:text-base">
|
| 215 |
+
Connexion
|
| 216 |
+
</a>
|
| 217 |
+
<a href="/inscription" class="px-3 py-1 sm:px-4 sm:py-2 border-2 border-green-500 text-green-500 hover:bg-green-500 hover:text-black font-medium transition duration-200 hidden sm:block text-sm sm:text-base">
|
| 218 |
+
Inscription
|
| 219 |
+
</a>
|
| 220 |
+
|
| 221 |
+
</nav>
|
| 222 |
+
</div>
|
| 223 |
+
</header>
|
| 224 |
+
|
| 225 |
+
<div class="pt-20 container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 226 |
+
|
| 227 |
+
<main class="space-y-24">
|
| 228 |
+
|
| 229 |
+
<section class="py-20"> <div class="flex flex-col items-start justify-start space-y-4"> <span class="material-symbols-rounded text-green-400 text-5xl mb-4">
|
| 230 |
+
mail_lock
|
| 231 |
+
</span>
|
| 232 |
+
|
| 233 |
+
<h1 id="animated-title" class="text-6xl sm:text-7xl font-bold text-color leading-tight mb-4"> Validez la Délivrabilité de Vos E-mails. En temps réel, avec l'API la Plus Rapide.
|
| 234 |
+
</h1>
|
| 235 |
+
<p class="text-2xl text-gray-300-var max-w-4xl mr-auto mb-10"> Éliminez les adresses e-mail non valides, jetables et à risque pour garantir des listes de diffusion propres et un meilleur ROI. <strong class="text-green-400">Une API simple, une validation instantanée.</strong>
|
| 236 |
+
</p>
|
| 237 |
+
|
| 238 |
+
<form class="flex flex-col sm:flex-row items-center w-full max-w-2xl bg-gray-900 border border-[var(--border-color)] rounded-lg p-1.5 shadow-2xl">
|
| 239 |
+
<input type="email" placeholder="Entrez un e-mail à tester (ex: test@exemple.com)" class="flex-grow w-full px-4 py-3 bg-transparent text-white placeholder-gray-500 focus:outline-none" required>
|
| 240 |
+
<button type="submit" class="w-full sm:w-auto mt-3 sm:mt-0 px-8 py-3 btn-primary text-lg font-bold rounded-lg whitespace-nowrap">
|
| 241 |
+
Tester la validité
|
| 242 |
+
</button>
|
| 243 |
+
</form>
|
| 244 |
+
</div>
|
| 245 |
+
<script>
|
| 246 |
+
const titleElement = document.getElementById('animated-title');
|
| 247 |
+
const text = "Validez la Délivrabilité de Vos E-mails. En temps réel, avec l'API la Plus Rapide.";
|
| 248 |
+
titleElement.innerHTML = text; // Assure que le texte est bien affiché
|
| 249 |
+
</script>
|
| 250 |
+
</section>
|
| 251 |
+
|
| 252 |
+
<section>
|
| 253 |
+
<h2 class="text-4xl font-bold text-color mb-8 text-center"> Analyse Technique Approfondie de l'Adresse.
|
| 254 |
+
</h2>
|
| 255 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 256 |
+
Nous allons au-delà de la syntaxe. Chaque e-mail passe par un processus de validation multi-étapes pour garantir sa livrabilité.
|
| 257 |
+
</p>
|
| 258 |
+
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
| 259 |
+
<div class="card-bg p-6 shadow-xl">
|
| 260 |
+
<span class="material-symbols-rounded text-3xl text-green-400 mb-3">dns</span> <h3 class="text-2xl font-semibold text-color mb-3">Vérification des Enregistrements MX</h3>
|
| 261 |
+
<p class="text-gray-300-var text-sm">Nous confirmons l'existence d'un serveur de messagerie valide (MX Record) pour le domaine, excluant les domaines non fonctionnels.</p>
|
| 262 |
+
</div>
|
| 263 |
+
<div class="card-bg p-6 shadow-xl">
|
| 264 |
+
<span class="material-symbols-rounded text-3xl text-yellow-400 mb-3">route</span> <h3 class="text-2xl font-semibold text-color mb-3">Vérification des Adresses A/PTR</h3>
|
| 265 |
+
<p class="text-gray-300-var text-sm">Validation du processus inverse (Reverse DNS) pour détecter les adresses de serveurs suspects ou mal configurés.</p>
|
| 266 |
+
</div>
|
| 267 |
+
<div class="card-bg p-6 shadow-xl">
|
| 268 |
+
<span class="material-symbols-rounded text-3xl text-purple-400 mb-3">connect_without_contact</span> <h3 class="text-2xl font-semibold text-color mb-3">Simulation SMTP</h3>
|
| 269 |
+
<p class="text-gray-300-var text-sm">Connexion à l'hôte pour confirmer la validité de la boîte de réception sans envoyer de message. Méthode non intrusive et précise.</p>
|
| 270 |
+
</div>
|
| 271 |
+
<div class="card-bg p-6 shadow-xl">
|
| 272 |
+
<span class="material-symbols-rounded text-3xl text-cyan-400 mb-3">timer</span> <h3 class="text-2xl font-semibold text-color mb-3">Analyse de Vitesse</h3>
|
| 273 |
+
<p class="text-gray-300-var text-sm">Le processus complet prend moins de 300ms, permettant une validation en temps réel sur vos formulaires d'inscription.</p>
|
| 274 |
+
</div>
|
| 275 |
+
</div>
|
| 276 |
+
</section>
|
| 277 |
+
|
| 278 |
+
<section class="py-12">
|
| 279 |
+
<h2 class="text-4xl font-bold text-color mb-4 text-center">
|
| 280 |
+
Technologies Supportées pour une Intégration Rapide.
|
| 281 |
+
</h2>
|
| 282 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 283 |
+
Mailix est conçu pour s'intégrer facilement dans n'importe quelle pile technologique, du frontend au backend.
|
| 284 |
+
</p>
|
| 285 |
+
|
| 286 |
+
<div class="logo-container">
|
| 287 |
+
<div class="logos-track" id="logos-track-content">
|
| 288 |
+
<div class="logo-item" title="Python"><img src="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" alt="Python Logo"></div>
|
| 289 |
+
<div class="logo-item" title="Node.js"><img src="https://upload.wikimedia.org/wikipedia/commons/d/d9/Node.js_logo.svg" alt="Node.js Logo"></div>
|
| 290 |
+
<div class="logo-item" title="PHP"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/PHP-logo.svg" alt="PHP Logo"></div>
|
| 291 |
+
<div class="logo-item" title="Ruby"><img src="https://upload.wikimedia.org/wikipedia/commons/7/73/Ruby_logo.svg" alt="Ruby Logo"></div>
|
| 292 |
+
|
| 293 |
+
<div class="logo-item" title="AWS (Amazon Web Services)"><img src="https://upload.wikimedia.org/wikipedia/commons/9/93/Amazon_Web_Services_Logo.svg" alt="AWS Logo"></div>
|
| 294 |
+
<div class="logo-item" title="Google Cloud Platform"><img src="https://upload.wikimedia.org/wikipedia/commons/5/51/Google_Cloud_logo.svg" alt="Google Cloud Logo"></div>
|
| 295 |
+
|
| 296 |
+
<div class="logo-item" title="React"><img src="https://upload.wikimedia.org/wikipedia/commons/a/a7/React-icon.svg" alt="React Logo"></div>
|
| 297 |
+
<div class="logo-item" title="Vue.js"><img src="https://upload.wikimedia.org/wikipedia/commons/9/95/Vue.js_Logo_2.svg" alt="Vue.js Logo"></div>
|
| 298 |
+
<div class="logo-item" title="Angular"><img src="https://upload.wikimedia.org/wikipedia/commons/c/cf/Angular_full_color_logo.svg" alt="Angular Logo"></div>
|
| 299 |
+
<div class="logo-item" title="Laravel"><img src="https://upload.wikimedia.org/wikipedia/commons/9/9a/Laravel.svg" alt="Laravel Logo"></div>
|
| 300 |
+
|
| 301 |
+
</div>
|
| 302 |
+
</div>
|
| 303 |
+
</section>
|
| 304 |
+
|
| 305 |
+
<section>
|
| 306 |
+
<h2 class="text-4xl font-bold text-color mb-8 text-center">
|
| 307 |
+
Cas d'Usage Détaillés pour l'Entreprise.
|
| 308 |
+
</h2>
|
| 309 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 310 |
+
Intégrez Mailix pour résoudre les défis critiques de votre pile marketing et de sécurité.
|
| 311 |
+
</p>
|
| 312 |
+
<div class="grid md:grid-cols-3 gap-6">
|
| 313 |
+
<div class="card-bg p-6">
|
| 314 |
+
<span class="material-symbols-rounded text-4xl text-green-500 mb-4">security</span>
|
| 315 |
+
<h3 class="text-2xl font-semibold text-color mb-3">Sécurisation des Inscriptions</h3>
|
| 316 |
+
<p class="text-gray-300-var">Validez les e-mails en temps réel sur vos formulaires pour bloquer les robots et les inscriptions frauduleuses dès le premier contact.</p>
|
| 317 |
+
</div>
|
| 318 |
+
<div class="card-bg p-6">
|
| 319 |
+
<span class="material-symbols-rounded text-4xl text-yellow-500 mb-4">cleaning_services</span>
|
| 320 |
+
<h3 class="text-2xl font-semibold text-color mb-3">Nettoyage de Base de Données</h3>
|
| 321 |
+
<p class="text-gray-300-var">Passez en revue et supprimez les e-mails obsolètes, invalides ou non livrables de vos listes existantes pour optimiser la réputation de votre expéditeur.</p>
|
| 322 |
+
</div>
|
| 323 |
+
<div class="card-bg p-6">
|
| 324 |
+
<span class="material-symbols-rounded text-4xl text-blue-500 mb-4">attach_money</span>
|
| 325 |
+
<h3 class="text-2xl font-semibold text-color mb-3">Prévention de la Fraude aux Promotions</h3>
|
| 326 |
+
<p class="text-gray-300-var">Détectez les adresses jetables utilisées pour abuser des offres de bienvenue ou des codes de réduction.</p>
|
| 327 |
+
</div>
|
| 328 |
+
</div>
|
| 329 |
+
</section>
|
| 330 |
+
<section>
|
| 331 |
+
<h2 class="text-4xl font-bold text-color mb-8 text-center"> Protection contre les Adresses Risquées.
|
| 332 |
+
</h2>
|
| 333 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 334 |
+
Réduisez votre taux de plaintes et de hard bounces en identifiant les e-mails nuisibles avant qu'ils n'atteignent votre liste.
|
| 335 |
+
</p>
|
| 336 |
+
<div class="grid md:grid-cols-3 gap-6">
|
| 337 |
+
<div class="card-bg p-6 text-center">
|
| 338 |
+
<span class="material-symbols-rounded text-4xl text-red-500 mb-4">block</span> <h3 class="text-2xl font-semibold text-color mb-3">E-mails Jetables (Temp Mail)</h3>
|
| 339 |
+
<p class="text-gray-300-var">Détection et blocage des domaines connus pour l'utilisation d'e-mails temporaires, qui nuisent à l'engagement à long terme.</p>
|
| 340 |
+
</div>
|
| 341 |
+
<div class="card-bg p-6 text-center">
|
| 342 |
+
<span class="material-symbols-rounded text-4xl text-indigo-400 mb-4">group</span> <h3 class="text-2xl font-semibold text-color mb-3">Rôles Génériques et Abusifs</h3>
|
| 343 |
+
<p class="text-gray-300-var">Identification des adresses génériques (`info@`, `support@`) ou potentiellement abusives, qui peuvent gonfler vos coûts.</p>
|
| 344 |
+
</div>
|
| 345 |
+
<div class="card-bg p-6 text-center">
|
| 346 |
+
<span class="material-symbols-rounded text-4xl text-pink-500 mb-4">skull</span> <h3 class="text-2xl font-semibold text-color mb-3">Domaines à Risque (Anti-Phishing)</h3>
|
| 347 |
+
<p class="text-gray-300-var">Base de données mise à jour en temps réel des domaines signalés pour le spam, l'hameçonnage ou les activités malveillantes.</p>
|
| 348 |
+
</div>
|
| 349 |
+
</div>
|
| 350 |
+
</section>
|
| 351 |
+
|
| 352 |
+
<section>
|
| 353 |
+
<h2 class="text-4xl font-bold text-color mb-8 text-center"> Performance et Scalabilité API.
|
| 354 |
+
</h2>
|
| 355 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 356 |
+
Gérez des volumes massifs avec notre API construite pour la vitesse, la fiabilité et le suivi précis de vos consommations.
|
| 357 |
+
</p>
|
| 358 |
+
<div class="grid md:grid-cols-3 gap-6">
|
| 359 |
+
<div class="card-bg p-6 text-center">
|
| 360 |
+
<span class="material-symbols-rounded text-4xl text-green-500 mb-4">rocket_launch</span> <h3 class="text-2xl font-semibold text-color mb-3">Vitesse Éclair</h3>
|
| 361 |
+
<p class="text-gray-300-var">Moins de 50ms de latence pour la majorité des requêtes. Validez en temps réel sans ralentir votre UX.</p>
|
| 362 |
+
</div>
|
| 363 |
+
<div class="card-bg p-6 text-center">
|
| 364 |
+
<span class="material-symbols-rounded text-4xl text-yellow-500 mb-4">monitoring</span> <h3 class="text-2xl font-semibold text-color mb-3">Dashboard de Consommation</h3>
|
| 365 |
+
<p class="text-gray-300-var">Suivez l'utilisation de vos crédits, le taux de validation et l'historique des appels via un tableau de bord intuitif.</p>
|
| 366 |
+
</div>
|
| 367 |
+
<div class="card-bg p-6 text-center">
|
| 368 |
+
<span class="material-symbols-rounded text-4xl text-blue-500 mb-4">vpn_key</span> <h3 class="text-2xl font-semibold text-color mb-3">Sécurité API</h3>
|
| 369 |
+
<p class="text-gray-300-var">Clés API sécurisées, protection contre les abus et conformité totale avec les standards OAuth 2.0.</p>
|
| 370 |
+
</div>
|
| 371 |
+
</div>
|
| 372 |
+
</section>
|
| 373 |
+
|
| 374 |
+
<section>
|
| 375 |
+
<h2 class="text-4xl font-bold text-color mb-6 text-center"> Intégration Instantanée
|
| 376 |
+
</h2>
|
| 377 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-8">
|
| 378 |
+
Validez une adresse e-mail en quelques lignes de code seulement.
|
| 379 |
+
</p>
|
| 380 |
+
|
| 381 |
+
<div class="w-full">
|
| 382 |
+
<div id="language-tabs" class="flex flex-wrap sm:flex-nowrap mb-0 border-b border-[var(--border-color)]">
|
| 383 |
+
<button data-lang="python" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-green-500 text-green-500 bg-gray-800 hover:bg-gray-700 flex-grow sm:flex-grow-0 transition duration-200">
|
| 384 |
+
Python
|
| 385 |
+
</button>
|
| 386 |
+
<button data-lang="javascript" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-transparent text-gray-400-var hover:text-white hover:bg-gray-800 flex-grow sm:flex-grow-0 transition duration-200">
|
| 387 |
+
JavaScript
|
| 388 |
+
</button>
|
| 389 |
+
<button data-lang="php" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-transparent text-gray-400-var hover:text-white hover:bg-gray-800 flex-grow sm:flex-grow-0 transition duration-200">
|
| 390 |
+
PHP
|
| 391 |
+
</button>
|
| 392 |
+
<button data-lang="bash" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-transparent text-gray-400-var hover:text-white hover:bg-gray-800 flex-grow sm:flex-grow-0 transition duration-200">
|
| 393 |
+
cURL (Bash)
|
| 394 |
+
</button>
|
| 395 |
+
</div>
|
| 396 |
+
|
| 397 |
+
<div id="code-content" class="code-block p-4 pt-6 text-sm">
|
| 398 |
+
|
| 399 |
+
<pre><code id="code-python" class="language-python tab-code">import requests
|
| 400 |
+
import json
|
| 401 |
+
|
| 402 |
+
# URL de l'API Mailix pour la validation d'e-mail
|
| 403 |
+
url = "https://mailix-mail-validation.api/api/validate"
|
| 404 |
+
headers = {"Content-Type": "application/json"}
|
| 405 |
+
payload = {"email": "utilisateur@example.com"}
|
| 406 |
+
|
| 407 |
+
# Envoi de la requête POST
|
| 408 |
+
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
| 409 |
+
print(response.json())
|
| 410 |
+
# Résultat: {"is_valid": true, "domain_status": "ok", "disposable": false}</code></pre>
|
| 411 |
+
|
| 412 |
+
<pre class="hidden"><code id="code-javascript" class="language-javascript tab-code">const validateEmail = async () => {
|
| 413 |
+
// URL de l'API Mailix pour la validation d'e-mail
|
| 414 |
+
const url = 'https://mailix-mail-validation.api/api/validate';
|
| 415 |
+
|
| 416 |
+
const response = await fetch(url, {
|
| 417 |
+
method: 'POST',
|
| 418 |
+
headers: { 'Content-Type': 'application/json' },
|
| 419 |
+
body: JSON.stringify({
|
| 420 |
+
email: 'utilisateur@example.com'
|
| 421 |
+
})
|
| 422 |
+
});
|
| 423 |
+
|
| 424 |
+
const data = await response.json();
|
| 425 |
+
console.log(data);
|
| 426 |
+
};
|
| 427 |
+
|
| 428 |
+
validateEmail();</code></pre>
|
| 429 |
+
|
| 430 |
+
<pre class="hidden"><code id="code-php" class="language-php tab-code"><?php
|
| 431 |
+
// URL de l'API Mailix pour la validation d'e-mail
|
| 432 |
+
$url = "https://mailix-mail-validation.api/api/validate";
|
| 433 |
+
$data = array("email" => "utilisateur@example.com");
|
| 434 |
+
|
| 435 |
+
$curl = curl_init();
|
| 436 |
+
|
| 437 |
+
curl_setopt_array($curl, array(
|
| 438 |
+
CURLOPT_URL => $url,
|
| 439 |
+
CURLOPT_RETURNTRANSFER => true,
|
| 440 |
+
CURLOPT_POST => true,
|
| 441 |
+
CURLOPT_HTTPHEADER => array('Content-Type: application/json'),
|
| 442 |
+
CURLOPT_POSTFIELDS => json_encode($data)
|
| 443 |
+
));
|
| 444 |
+
|
| 445 |
+
$response = curl_exec($curl);
|
| 446 |
+
curl_close($curl);
|
| 447 |
+
print_r(json_decode($response, true));
|
| 448 |
+
?></code></pre>
|
| 449 |
+
|
| 450 |
+
<pre class="hidden"><code id="code-bash" class="language-bash tab-code"># URL de l'API Mailix pour la validation d'e-mail
|
| 451 |
+
curl -X POST \
|
| 452 |
+
-H "Content-Type: application/json" \
|
| 453 |
+
-d '{"email": "utilisateur@example.com"}' \
|
| 454 |
+
"https://mailix-mail-validation.api/api/validate"</code></pre>
|
| 455 |
+
</div>
|
| 456 |
+
</div>
|
| 457 |
+
</section>
|
| 458 |
+
|
| 459 |
+
<section class="bg-green-900/40 p-8 shadow-xl border border-green-600">
|
| 460 |
+
<div class="flex flex-col md:flex-row items-center space-y-4 md:space-y-0 md:space-x-8">
|
| 461 |
+
<span class="material-symbols-rounded w-12 h-12 text-green-400 flex-shrink-0 text-5xl">bolt</span> <div>
|
| 462 |
+
<h3 class="text-3xl font-bold text-color mb-2">Conçu pour l'Évolutivité Illimitée</h3>
|
| 463 |
+
<p class="text-green-200">
|
| 464 |
+
Notre architecture est élastique. De 10 à 10 millions de validations, Mailix s'adapte automatiquement. Atteignez la croissance sans jamais vous soucier des limites techniques. Découvrez notre <a href="/documentation" class="text-yellow-400 underline font-semibold">documentation d'architecture</a>.
|
| 465 |
+
</p>
|
| 466 |
+
</div>
|
| 467 |
+
</div>
|
| 468 |
+
</section>
|
| 469 |
+
|
| 470 |
+
<section>
|
| 471 |
+
<h2 class="text-4xl font-bold text-color mb-4 text-center"> La sécurité est notre priorité absolue.
|
| 472 |
+
</h2>
|
| 473 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 474 |
+
Dormez sur vos deux oreilles grâce à une plateforme qui respecte les standards les plus stricts du marché.
|
| 475 |
+
</p>
|
| 476 |
+
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
| 477 |
+
<div class="card-bg p-6 space-y-2">
|
| 478 |
+
<span class="material-symbols-rounded text-2xl text-green-400">shield_with_key</span> <h3 class="font-semibold text-color">Validation Multi-Facteur</h3>
|
| 479 |
+
<p class="text-gray-300-var text-sm">Prise en charge native et intégrée des jetons TOTP et des clés de sécurité WebAuthn pour un niveau de protection supérieur.</p>
|
| 480 |
+
</div>
|
| 481 |
+
<div class="card-bg p-6 space-y-2">
|
| 482 |
+
<span class="material-symbols-rounded text-2xl text-green-400">encrypted</span>
|
| 483 |
+
<h3 class="font-semibold text-color">Chiffrement Complet</h3>
|
| 484 |
+
<p class="text-gray-300-var text-sm">Chiffrement des données de l'utilisateur au repos (AES-256) et communication sécurisée via TLS/SSL.</p>
|
| 485 |
+
</div>
|
| 486 |
+
<div class="card-bg p-6 space-y-2">
|
| 487 |
+
<span class="material-symbols-rounded text-2xl text-purple-400">balance</span>
|
| 488 |
+
<h3 class="font-semibold text-color">Conformité RGPD / CCPA</h3>
|
| 489 |
+
<p class="text-gray-300-var text-sm">Gestion des données utilisateurs conforme aux réglementations mondiales (RGPD, CCPA, etc.).</p>
|
| 490 |
+
</div>
|
| 491 |
+
<div class="card-bg p-6 space-y-2">
|
| 492 |
+
<span class="material-symbols-rounded text-2xl text-yellow-400">link</span>
|
| 493 |
+
<h3 class="font-semibold text-color">Standards Ouverts</h3>
|
| 494 |
+
<p class="text-gray-300-var text-sm">Support natif et complet des protocoles OAuth 2.0, OpenID Connect (OIDC) et SAML 2.0.</p>
|
| 495 |
+
</div>
|
| 496 |
+
<div class="card-bg p-6 space-y-2">
|
| 497 |
+
<span class="material-symbols-rounded text-2xl text-teal-400">history_toggle_off</span>
|
| 498 |
+
<h3 class="font-semibold text-color">Journaux d'Audit (Logs)</h3>
|
| 499 |
+
<p class="text-gray-300-var text-sm">Historique des événements de validation et d'accès en temps réel pour le monitoring et la traçabilité.</p>
|
| 500 |
+
</div>
|
| 501 |
+
<div class="card-bg p-6 space-y-2">
|
| 502 |
+
<span class="material-symbols-rounded text-2xl text-pink-400">group_add</span>
|
| 503 |
+
<h3 class="font-semibold text-color">Authentification Fédérée</h3>
|
| 504 |
+
<p class="text-gray-300-var text-sm">Connexion facilitée via les fournisseurs d'identité sociaux et d'entreprise (Google, Microsoft, etc.).</p>
|
| 505 |
+
</div>
|
| 506 |
+
<div class="card-bg p-6 space-y-2">
|
| 507 |
+
<span class="material-symbols-rounded text-2xl text-red-400">sos</span>
|
| 508 |
+
<h3 class="font-semibold text-color">Prévention des Attaques</h3>
|
| 509 |
+
<p class="text-gray-300-var text-sm">Limitation de taux (Rate Limiting), détection de bots et blocage des IP malveillantes automatique.</p>
|
| 510 |
+
</div>
|
| 511 |
+
<div class="card-bg p-6 space-y-2">
|
| 512 |
+
<span class="material-symbols-rounded text-2xl text-indigo-400">bug_report</span>
|
| 513 |
+
<h3 class="font-semibold text-color">Programme Bug Bounty</h3>
|
| 514 |
+
<p class="text-gray-300-var text-sm">Collaboration avec la communauté de la sécurité pour identifier et corriger les vulnérabilités en continu.</p>
|
| 515 |
+
</div>
|
| 516 |
+
</div>
|
| 517 |
+
</section>
|
| 518 |
+
|
| 519 |
+
<section>
|
| 520 |
+
<h2 class="text-4xl font-bold text-color mb-4 text-center"> Statistiques de Performance Clés
|
| 521 |
+
</h2>
|
| 522 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 523 |
+
L'architecture globale de Mailix garantit fiabilité et rapidité, essentielles à votre infrastructure.
|
| 524 |
+
</p>
|
| 525 |
+
|
| 526 |
+
<div class="grid md:grid-cols-3 gap-8 mb-12 text-center">
|
| 527 |
+
<div class="card-bg p-6 shadow-xl">
|
| 528 |
+
<h4 class="text-5xl font-bold text-green-400 mb-2">99.99%</h4>
|
| 529 |
+
<p class="text-lg font-semibold text-color">SLA Garanti</p>
|
| 530 |
+
<p class="text-gray-300-var text-sm">Fiabilité maximale, votre service est toujours disponible.</p>
|
| 531 |
+
</div>
|
| 532 |
+
<div class="card-bg p-6 shadow-xl">
|
| 533 |
+
<h4 class="text-5xl font-bold text-orange-400 mb-2">< 50ms</h4>
|
| 534 |
+
<p class="text-lg font-semibold text-color">Latence Globale</p>
|
| 535 |
+
<p class="text-gray-300-var text-sm">Temps de réponse de l'API optimisé pour une expérience utilisateur rapide.</p>
|
| 536 |
+
</div>
|
| 537 |
+
<div class="card-bg p-6 shadow-xl">
|
| 538 |
+
<h4 class="text-5xl font-bold text-lime-400 mb-2">10M+</h4>
|
| 539 |
+
<p class="text-lg font-semibold text-color">Validations / Mois</p>
|
| 540 |
+
<p class="text-gray-300-var text-sm">Capacité à gérer la croissance horizontale et les pics de trafic sans effort.</p>
|
| 541 |
+
</div>
|
| 542 |
+
</div>
|
| 543 |
+
</section>
|
| 544 |
+
|
| 545 |
+
<section class="py-12"> <h2 class="text-4xl font-bold text-color mb-4 text-center"> Ce que nos clients disent de Mailix.
|
| 546 |
+
</h2>
|
| 547 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 548 |
+
Plus de 15 témoignages qui illustrent la puissance et la fiabilité de notre plateforme.
|
| 549 |
+
</p>
|
| 550 |
+
|
| 551 |
+
<div class="testimonial-container">
|
| 552 |
+
<div class="testimonials-track" id="testimonials-track-content">
|
| 553 |
+
<div class="testimonial-card p-6">
|
| 554 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Mailix a réduit nos temps d'intégration de trois semaines à deux jours. La documentation est impeccable et le support réactif."</p>
|
| 555 |
+
<div class="flex flex-col">
|
| 556 |
+
<div class="flex items-center mb-2">
|
| 557 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 558 |
+
J
|
| 559 |
+
</div>
|
| 560 |
+
<div>
|
| 561 |
+
<p class="font-bold text-color">Jean Dupont</p>
|
| 562 |
+
<p class="text-sm text-gray-400-var">CTO chez TechFusion</p>
|
| 563 |
+
</div>
|
| 564 |
+
</div>
|
| 565 |
+
<a href="mailto:jean.dupont@techfusion.com" class="text-sm font-medium text-blue-500-var hover:underline">jean.dupont@techfusion.com</a>
|
| 566 |
+
</div>
|
| 567 |
+
</div>
|
| 568 |
+
<div class="testimonial-card p-6">
|
| 569 |
+
<p class="text-xl italic text-gray-300-var mb-4">"La bascule vers Mailix a été un jeu d'enfant. Notre taux d'erreur d'authentification est tombé à presque zéro."</p>
|
| 570 |
+
<div class="flex flex-col">
|
| 571 |
+
<div class="flex items-center mb-2">
|
| 572 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 573 |
+
S
|
| 574 |
+
</div>
|
| 575 |
+
<div>
|
| 576 |
+
<p class="font-bold text-color">Sophie Martin</p>
|
| 577 |
+
<p class="text-sm text-gray-400-var">Développeuse Lead chez InnovApp</p>
|
| 578 |
+
</div>
|
| 579 |
+
</div>
|
| 580 |
+
<a href="mailto:sophie.martin@innovapp.fr" class="text-sm font-medium text-blue-500-var hover:underline">sophie.martin@innovapp.fr</a>
|
| 581 |
+
</div>
|
| 582 |
+
</div>
|
| 583 |
+
<div class="testimonial-card p-6">
|
| 584 |
+
<p class="text-xl italic text-gray-300-var mb-4">"La fonction MFA intégrée a été essentielle pour la conformité de notre plateforme B2B. Un outil robuste et fiable."</p>
|
| 585 |
+
<div class="flex flex-col">
|
| 586 |
+
<div class="flex items-center mb-2">
|
| 587 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 588 |
+
D
|
| 589 |
+
</div>
|
| 590 |
+
<div>
|
| 591 |
+
<p class="font-bold text-color">David Dubois</p>
|
| 592 |
+
<p class="text-sm text-gray-400-var">Chef de Produit chez GlobalSec</p>
|
| 593 |
+
</div>
|
| 594 |
+
</div>
|
| 595 |
+
<a href="mailto:david.dubois@globalsec.com" class="text-sm font-medium text-blue-500-var hover:underline">david.dubois@globalsec.com</a>
|
| 596 |
+
</div>
|
| 597 |
+
</div>
|
| 598 |
+
<div class="testimonial-card p-6">
|
| 599 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Scalabilité prouvée : nous avons géré notre pic de Noël sans la moindre latence. Chapeau à l'équipe Mailix."</p>
|
| 600 |
+
<div class="flex flex-col">
|
| 601 |
+
<div class="flex items-center mb-2">
|
| 602 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 603 |
+
M
|
| 604 |
+
</div>
|
| 605 |
+
<div>
|
| 606 |
+
<p class="font-bold text-color">Marc Lavoie</p>
|
| 607 |
+
<p class="text-sm text-gray-400-var">Architecte Cloud chez E-Commerce X</p>
|
| 608 |
+
</div>
|
| 609 |
+
</div>
|
| 610 |
+
<a href="mailto:marc.lavoie@ecommercex.ca" class="text-sm font-medium text-blue-500-var hover:underline">marc.lavoie@ecommercex.ca</a>
|
| 611 |
+
</div>
|
| 612 |
+
</div>
|
| 613 |
+
<div class="testimonial-card p-6">
|
| 614 |
+
<p class="text-xl italic text-gray-300-var mb-4">"La rapidité de validation nous a permis de réduire notre taux de bounce de 15%."</p>
|
| 615 |
+
<div class="flex flex-col">
|
| 616 |
+
<div class="flex items-center mb-2">
|
| 617 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 618 |
+
E
|
| 619 |
+
</div>
|
| 620 |
+
<div>
|
| 621 |
+
<p class="font-bold text-color">Emma Tremblay</p>
|
| 622 |
+
<p class="text-sm text-gray-400-var">Responsable Marketing chez CreativeHub</p>
|
| 623 |
+
</div>
|
| 624 |
+
</div>
|
| 625 |
+
<a href="mailto:emma.tremblay@creativehub.com" class="text-sm font-medium text-blue-500-var hover:underline">emma.tremblay@creativehub.com</a>
|
| 626 |
+
</div>
|
| 627 |
+
</div>
|
| 628 |
+
<div class="testimonial-card p-6">
|
| 629 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Une API propre et simple. Moins de temps passé sur la validation, plus sur notre cœur de métier."</p>
|
| 630 |
+
<div class="flex flex-col">
|
| 631 |
+
<div class="flex items-center mb-2">
|
| 632 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 633 |
+
L
|
| 634 |
+
</div>
|
| 635 |
+
<div>
|
| 636 |
+
<p class="font-bold text-color">Lucas Petit</p>
|
| 637 |
+
<p class="text-sm text-gray-400-var">Dev Backend chez DataStream</p>
|
| 638 |
+
</div>
|
| 639 |
+
</div>
|
| 640 |
+
<a href="mailto:lucas.petit@datastream.io" class="text-sm font-medium text-blue-500-var hover:underline">lucas.petit@datastream.io</a>
|
| 641 |
+
</div>
|
| 642 |
+
</div>
|
| 643 |
+
<div class="testimonial-card p-6">
|
| 644 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Le meilleur rapport performance/prix pour une solution d'authentification d'entreprise. Je recommande fortement."</p>
|
| 645 |
+
<div class="flex flex-col">
|
| 646 |
+
<div class="flex items-center mb-2">
|
| 647 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 648 |
+
C
|
| 649 |
+
</div>
|
| 650 |
+
<div>
|
| 651 |
+
<p class="font-bold text-color">Chloé Lefevre</p>
|
| 652 |
+
<p class="text-sm text-gray-400-var">COO chez FinTech Z</p>
|
| 653 |
+
</div>
|
| 654 |
+
</div>
|
| 655 |
+
<a href="mailto:chloe.lefevre@fintechz.com" class="text-sm font-medium text-blue-500-var hover:underline">chloe.lefevre@fintechz.com</a>
|
| 656 |
+
</div>
|
| 657 |
+
</div>
|
| 658 |
+
<div class="testimonial-card p-6">
|
| 659 |
+
<p class="text-xl italic text-gray-300-var mb-4">"La transition des données de notre ancien système a été la partie la plus facile de notre refonte, grâce aux outils Mailix."</p>
|
| 660 |
+
<div class="flex flex-col">
|
| 661 |
+
<div class="flex items-center mb-2">
|
| 662 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 663 |
+
A
|
| 664 |
+
</div>
|
| 665 |
+
<div>
|
| 666 |
+
<p class="font-bold text-color">Alexandre Roy</p>
|
| 667 |
+
<p class="text-sm text-gray-400-var">Ingénieur DevOps chez Legacy Solutions</p>
|
| 668 |
+
</div>
|
| 669 |
+
</div>
|
| 670 |
+
<a href="mailto:alexandre.roy@legacy.io" class="text-sm font-medium text-blue-500-var hover:underline">alexandre.roy@legacy.io</a>
|
| 671 |
+
</div>
|
| 672 |
+
</div>
|
| 673 |
+
<div class="testimonial-card p-6">
|
| 674 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Mailix est le standard de facto pour la gestion des identités modernes. Nous ne regardons plus en arrière."</p>
|
| 675 |
+
<div class="flex flex-col">
|
| 676 |
+
<div class="flex items-center mb-2">
|
| 677 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 678 |
+
J
|
| 679 |
+
</div>
|
| 680 |
+
<div>
|
| 681 |
+
<p class="font-bold text-color">Julie Gauthier</p>
|
| 682 |
+
<p class="text-sm text-gray-400-var">VP Engineering chez FuturePath</p>
|
| 683 |
+
</div>
|
| 684 |
+
</div>
|
| 685 |
+
<a href="mailto:julie.gauthier@futurepath.com" class="text-sm font-medium text-blue-500-var hover:underline">julie.gauthier@futurepath.com</a>
|
| 686 |
+
</div>
|
| 687 |
+
</div>
|
| 688 |
+
<div class="testimonial-card p-6">
|
| 689 |
+
<p class="text-xl italic text-gray-300-var mb-4">"La surveillance des logs en temps réel nous permet d'identifier et de répondre aux menaces instantanément."</p>
|
| 690 |
+
<div class="flex flex-col">
|
| 691 |
+
<div class="flex items-center mb-2">
|
| 692 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 693 |
+
N
|
| 694 |
+
</div>
|
| 695 |
+
<div>
|
| 696 |
+
<p class="font-bold text-color">Nicolas Bernard</p>
|
| 697 |
+
<p class="text-sm text-gray-400-var">Spécialiste Cybersécurité chez SecureNet</p>
|
| 698 |
+
</div>
|
| 699 |
+
</div>
|
| 700 |
+
<a href="mailto:nicolas.bernard@securenet.io" class="text-sm font-medium text-blue-500-var hover:underline">nicolas.bernard@securenet.io</a>
|
| 701 |
+
</div>
|
| 702 |
+
</div>
|
| 703 |
+
<div class="testimonial-card p-6">
|
| 704 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Nos clients B2B apprécient la facilité du SSO. C'est un argument de vente majeur pour nous."</p>
|
| 705 |
+
<div class="flex flex-col">
|
| 706 |
+
<div class="flex items-center mb-2">
|
| 707 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 708 |
+
C
|
| 709 |
+
</div>
|
| 710 |
+
<div>
|
| 711 |
+
<p class="font-bold text-color">Caroline Gagnon</p>
|
| 712 |
+
<p class="text-sm text-gray-400-var">Directrice Commerciale chez B2B Connect</p>
|
| 713 |
+
</div>
|
| 714 |
+
</div>
|
| 715 |
+
<a href="mailto:caroline.gagnon@b2bconnect.ca" class="text-sm font-medium text-blue-500-var hover:underline">caroline.gagnon@b2bconnect.ca</a>
|
| 716 |
+
</div>
|
| 717 |
+
</div>
|
| 718 |
+
<div class="testimonial-card p-6">
|
| 719 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Les SDKs sont incroyablement bien documentés. Intégration en moins d'une heure pour notre application React."</p>
|
| 720 |
+
<div class="flex flex-col">
|
| 721 |
+
<div class="flex items-center mb-2">
|
| 722 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 723 |
+
F
|
| 724 |
+
</div>
|
| 725 |
+
<div>
|
| 726 |
+
<p class="font-bold text-color">Frédéric Leblanc</p>
|
| 727 |
+
<p class="text-sm text-gray-400-var">Développeur Frontend chez App Studio</p>
|
| 728 |
+
</div>
|
| 729 |
+
</div>
|
| 730 |
+
<a href="mailto:frederic.leblanc@appstudio.com" class="text-sm font-medium text-blue-500-var hover:underline">frederic.leblanc@appstudio.com</a>
|
| 731 |
+
</div>
|
| 732 |
+
</div>
|
| 733 |
+
<div class="testimonial-card p-6">
|
| 734 |
+
<p class="text-xl italic text-gray-300-var mb-4">"Mailix a réduit nos temps d'intégration de trois semaines à deux jours. La documentation est impeccable et le support réactif."</p>
|
| 735 |
+
<div class="flex flex-col">
|
| 736 |
+
<div class="flex items-center mb-2">
|
| 737 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 738 |
+
J
|
| 739 |
+
</div>
|
| 740 |
+
<div>
|
| 741 |
+
<p class="font-bold text-color">Jean Dupont</p>
|
| 742 |
+
<p class="text-sm text-gray-400-var">CTO chez TechFusion</p>
|
| 743 |
+
</div>
|
| 744 |
+
</div>
|
| 745 |
+
<a href="mailto:jean.dupont@techfusion.com" class="text-sm font-medium text-blue-500-var hover:underline">jean.dupont@techfusion.com</a>
|
| 746 |
+
</div>
|
| 747 |
+
</div>
|
| 748 |
+
<div class="testimonial-card p-6">
|
| 749 |
+
<p class="text-xl italic text-gray-300-var mb-4">"La bascule vers Mailix a été un jeu d'enfant. Notre taux d'erreur d'authentification est tombé à presque zéro."</p>
|
| 750 |
+
<div class="flex flex-col">
|
| 751 |
+
<div class="flex items-center mb-2">
|
| 752 |
+
<div class="w-10 h-10 bg-green-500 flex items-center justify-center text-black font-bold text-lg mr-3">
|
| 753 |
+
S
|
| 754 |
+
</div>
|
| 755 |
+
<div>
|
| 756 |
+
<p class="font-bold text-color">Sophie Martin</p>
|
| 757 |
+
<p class="text-sm text-gray-400-var">Développeuse Lead chez InnovApp</p>
|
| 758 |
+
</div>
|
| 759 |
+
</div>
|
| 760 |
+
<a href="mailto:sophie.martin@innovapp.fr" class="text-sm font-medium text-blue-500-var hover:underline">sophie.martin@innovapp.fr</a>
|
| 761 |
+
</div>
|
| 762 |
+
</div>
|
| 763 |
+
</div>
|
| 764 |
+
</div>
|
| 765 |
+
</section>
|
| 766 |
+
|
| 767 |
+
<section class="py-12">
|
| 768 |
+
<h2 class="text-4xl font-bold text-color mb-4 text-center">
|
| 769 |
+
FAQ (Foire Aux Questions)
|
| 770 |
+
</h2>
|
| 771 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-12">
|
| 772 |
+
Trouvez rapidement les réponses à vos questions techniques et commerciales.
|
| 773 |
+
</p>
|
| 774 |
+
|
| 775 |
+
<div class="max-w-4xl mx-auto divide-y divide-[var(--border-color)] border-y border-[var(--border-color)]">
|
| 776 |
+
|
| 777 |
+
<details class="faq-item">
|
| 778 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 779 |
+
Qu'est-ce que la "Simulation SMTP" ?
|
| 780 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 781 |
+
</summary>
|
| 782 |
+
<p class="pb-4 text-gray-300-var">
|
| 783 |
+
La simulation SMTP est un test non intrusif où notre API se connecte au serveur de messagerie du destinataire et commence la procédure d'envoi, mais coupe la connexion avant d'envoyer le message final. Cela permet de confirmer l'existence et la validité de la boîte de réception sans générer de trafic e-mail indésirable.
|
| 784 |
+
</p>
|
| 785 |
+
</details>
|
| 786 |
+
|
| 787 |
+
<details class="faq-item">
|
| 788 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 789 |
+
Quel est le temps de latence moyen de l'API Mailix ?
|
| 790 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 791 |
+
</summary>
|
| 792 |
+
<p class="pb-4 text-gray-300-var">
|
| 793 |
+
Notre architecture distribuée et optimisée nous permet d'atteindre une latence moyenne inférieure à 50ms pour la majorité des requêtes. Cette vitesse est cruciale pour la validation d'e-mails en temps réel sur les formulaires de vos utilisateurs.
|
| 794 |
+
</p>
|
| 795 |
+
</details>
|
| 796 |
+
|
| 797 |
+
<details class="faq-item">
|
| 798 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 799 |
+
Comment gérez-vous la conformité RGPD et CCPA ?
|
| 800 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 801 |
+
</summary>
|
| 802 |
+
<p class="pb-4 text-gray-300-var">
|
| 803 |
+
Nous sommes entièrement conformes aux réglementations RGPD (Europe) et CCPA (Californie). Nous ne stockons aucune donnée personnelle au-delà de la durée nécessaire à la validation et nos serveurs sont configurés pour respecter les exigences de résidence des données.
|
| 804 |
+
</p>
|
| 805 |
+
</details>
|
| 806 |
+
|
| 807 |
+
<details class="faq-item">
|
| 808 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 809 |
+
Qu'est-ce qu'un "E-mail Jetable" et pourquoi le bloquer ?
|
| 810 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 811 |
+
</summary>
|
| 812 |
+
<p class="pb-4 text-gray-300-var">
|
| 813 |
+
Un e-mail jetable (ou temp mail) est une adresse éphémère qui expire après une courte période. Les utilisateurs les emploient souvent pour s'inscrire à des services sans intention d'engagement à long terme. Les bloquer permet de maintenir la qualité de votre liste et d'éviter les faux utilisateurs.
|
| 814 |
+
</p>
|
| 815 |
+
</details>
|
| 816 |
+
|
| 817 |
+
<details class="faq-item">
|
| 818 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 819 |
+
L'API supporte-t-elle les validations en masse ?
|
| 820 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 821 |
+
</summary>
|
| 822 |
+
<p class="pb-4 text-gray-300-var">
|
| 823 |
+
Oui, notre API est conçue pour la scalabilité et peut gérer de grands volumes de validation. Pour les nettoyages de base de données massifs, nous proposons également une fonctionnalité de validation de liste asynchrone pour traiter des millions d'adresses efficacement.
|
| 824 |
+
</p>
|
| 825 |
+
</details>
|
| 826 |
+
|
| 827 |
+
<details class="faq-item">
|
| 828 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 829 |
+
Quels sont les mécanismes de sécurité mis en place pour l'accès API ?
|
| 830 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 831 |
+
</summary>
|
| 832 |
+
<p class="pb-4 text-gray-300-var">
|
| 833 |
+
Nous utilisons des clés API sécurisées, conformes à OAuth 2.0. Toutes les communications sont chiffrées via TLS/SSL. De plus, nous appliquons une limitation de taux (Rate Limiting) agressive et une détection de bots pour prévenir les abus et les attaques DDoS.
|
| 834 |
+
</p>
|
| 835 |
+
</details>
|
| 836 |
+
|
| 837 |
+
<details class="faq-item">
|
| 838 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 839 |
+
Puis-je tester la validité d'un e-mail directement sur votre site ?
|
| 840 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 841 |
+
</summary>
|
| 842 |
+
<p class="pb-4 text-gray-300-var">
|
| 843 |
+
Absolument. La section d'introduction de cette page contient un champ de test en temps réel qui utilise notre API principale pour vous donner un aperçu instantané de nos capacités de validation.
|
| 844 |
+
</p>
|
| 845 |
+
</details>
|
| 846 |
+
|
| 847 |
+
<details class="faq-item">
|
| 848 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 849 |
+
Qu'est-ce qu'une vérification des Enregistrements MX ?
|
| 850 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 851 |
+
</summary>
|
| 852 |
+
<p class="pb-4 text-gray-300-var">
|
| 853 |
+
C'est la première étape technique pour s'assurer que le domaine de l'e-mail peut recevoir du courrier. Nous vérifions l'existence d'un enregistrement MX (Mail Exchanger) dans le DNS du domaine, ce qui est essentiel pour la livrabilité. Si cet enregistrement est manquant, l'e-mail est invalide.
|
| 854 |
+
</p>
|
| 855 |
+
</details>
|
| 856 |
+
|
| 857 |
+
<details class="faq-item">
|
| 858 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 859 |
+
Comment puis-je suivre ma consommation de crédits API ?
|
| 860 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 861 |
+
</summary>
|
| 862 |
+
<p class="pb-4 text-gray-300-var">
|
| 863 |
+
Chaque client a accès à un tableau de bord intuitif où il peut suivre en temps réel l'utilisation des crédits, les taux de validation, les statistiques d'erreur et l'historique détaillé de tous les appels API effectués.
|
| 864 |
+
</p>
|
| 865 |
+
</details>
|
| 866 |
+
|
| 867 |
+
<details class="faq-item">
|
| 868 |
+
<summary class="text-lg text-color hover:text-green-400 transition duration-200">
|
| 869 |
+
Supportez-vous l'Authentification Fédérée (SSO) pour les clients B2B ?
|
| 870 |
+
<span class="material-symbols-rounded faq-icon text-green-400">add</span>
|
| 871 |
+
</summary>
|
| 872 |
+
<p class="pb-4 text-gray-300-var">
|
| 873 |
+
Oui, nous supportons entièrement l'Authentification Fédérée via des protocoles comme OAuth 2.0, OpenID Connect et SAML 2.0, permettant une connexion simplifiée pour vos clients d'entreprise via leurs fournisseurs d'identité (Google, Microsoft, Okta, etc.).
|
| 874 |
+
</p>
|
| 875 |
+
</details>
|
| 876 |
+
|
| 877 |
+
</div>
|
| 878 |
+
</section>
|
| 879 |
+
</main>
|
| 880 |
+
|
| 881 |
+
<script>
|
| 882 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 883 |
+
const track = document.getElementById('testimonials-track-content');
|
| 884 |
+
if (track) {
|
| 885 |
+
const cards = track.querySelectorAll('.testimonial-card');
|
| 886 |
+
// Dupliquer les cartes pour créer l'effet de défilement infini
|
| 887 |
+
cards.forEach(card => {
|
| 888 |
+
const clone = card.cloneNode(true);
|
| 889 |
+
track.appendChild(clone);
|
| 890 |
+
});
|
| 891 |
+
}
|
| 892 |
+
});
|
| 893 |
+
</script>
|
| 894 |
+
</div>
|
| 895 |
+
|
| 896 |
+
<script>
|
| 897 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 898 |
+
const track = document.getElementById('logos-track-content');
|
| 899 |
+
if (track) {
|
| 900 |
+
const logos = track.querySelectorAll('.logo-item');
|
| 901 |
+
// Dupliquer les logos pour créer l'effet de défilement infini
|
| 902 |
+
logos.forEach(logo => {
|
| 903 |
+
const clone = logo.cloneNode(true);
|
| 904 |
+
track.appendChild(clone);
|
| 905 |
+
});
|
| 906 |
+
}
|
| 907 |
+
});
|
| 908 |
+
</script>
|
| 909 |
+
|
| 910 |
+
|
| 911 |
+
|
| 912 |
+
|
| 913 |
+
<footer class="mt-20 py-10 bg-header border-t header-border">
|
| 914 |
+
<div class="container mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
| 915 |
+
<div class="grid grid-cols-4 gap-8 text-sm">
|
| 916 |
+
|
| 917 |
+
<div class="col-span-4 md:col-span-1">
|
| 918 |
+
<h3 class="text-2xl font-bold text-green-500 mb-4">Mailix</h3> <p class="text-gray-400-var">La plateforme de validation d'e-mails la plus rapide pour vos besoins d'entreprise. Zéro Spam, Zéro Bounce.</p>
|
| 919 |
+
</div>
|
| 920 |
+
|
| 921 |
+
<div class="col-span-2 md:col-span-1">
|
| 922 |
+
<h3 class="text-lg font-semibold text-color mb-4">Produit</h3>
|
| 923 |
+
<ul class="space-y-3 text-gray-400-var">
|
| 924 |
+
<li><a href="/tarifs" class="hover:text-blue-500-var transition duration-200">Tarifs</a></li>
|
| 925 |
+
<li><a href="/fonctionnalites" class="hover:text-blue-500-var transition duration-200">Fonctionnalités</a></li>
|
| 926 |
+
<li><a href="/documentation" class="hover:text-blue-500-var transition duration-200">Documentation</a></li>
|
| 927 |
+
<li><a href="/support" class="hover:text-blue-500-var transition duration-200">Support</a></li>
|
| 928 |
+
</ul>
|
| 929 |
+
</div>
|
| 930 |
+
|
| 931 |
+
<div class="col-span-2 md:col-span-1">
|
| 932 |
+
<h3 class="text-lg font-semibold text-color mb-4">Légal</h3>
|
| 933 |
+
<ul class="space-y-3 text-gray-400-var">
|
| 934 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500-var transition duration-200">Politique de Confidentialité</a></li>
|
| 935 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500-var transition duration-200">Mentions Légales</a></li>
|
| 936 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500-var transition duration-200">Conditions d'Utilisation</a></li>
|
| 937 |
+
<li><a href="/a-propos" class="hover:text-blue-500-var transition duration-200">À Propos</a></li>
|
| 938 |
+
</ul>
|
| 939 |
+
</div>
|
| 940 |
+
|
| 941 |
+
<div class="col-span-2 md:col-span-1">
|
| 942 |
+
<h3 class="text-lg font-semibold text-color mb-4">Ressources</h3>
|
| 943 |
+
<ul class="space-y-3 text-gray-400-var">
|
| 944 |
+
<li><a href="mailto:support@mailix.com" class="hover:text-blue-500-var transition duration-200">Contact Email</a></li>
|
| 945 |
+
<li><a href="/dashboard" class="hover:text-blue-500-var transition duration-200">Espace Client</a></li>
|
| 946 |
+
<li><a href="/api-logs" class="hover:text-blue-500-var transition duration-200">Statut API</a></li>
|
| 947 |
+
</ul>
|
| 948 |
+
</div>
|
| 949 |
+
|
| 950 |
+
</div>
|
| 951 |
+
|
| 952 |
+
<div class="mt-10 pt-6 border-t border-[var(--border-color)]">
|
| 953 |
+
<p class="text-center text-sm text-gray-500-var">
|
| 954 |
+
© 2025 Mailix. Tous droits réservés. Propulsé par la <a href="/" class="hover:text-blue-500-var transition duration-200">Validation d'E-mail la plus rapide</a>.
|
| 955 |
+
</p>
|
| 956 |
+
</div>
|
| 957 |
+
</div>
|
| 958 |
+
</footer>
|
| 959 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
| 960 |
+
<script>
|
| 961 |
+
// Initialiser Highlight.js pour les blocs de code
|
| 962 |
+
hljs.highlightAll();
|
| 963 |
+
|
| 964 |
+
// Logique de l'onglet de code mise à jour (couleurs déjà en CSS)
|
| 965 |
+
document.getElementById('language-tabs').addEventListener('click', function(e) {
|
| 966 |
+
if (e.target.classList.contains('tab-button')) {
|
| 967 |
+
// Désactiver tous les onglets
|
| 968 |
+
document.querySelectorAll('.tab-button').forEach(btn => {
|
| 969 |
+
btn.classList.remove('border-green-500', 'text-green-500', 'bg-gray-800');
|
| 970 |
+
btn.classList.add('border-transparent', 'text-gray-400-var', 'hover:text-white', 'hover:bg-gray-800');
|
| 971 |
+
});
|
| 972 |
+
|
| 973 |
+
// Cacher tous les blocs de code
|
| 974 |
+
document.querySelectorAll('.tab-code').forEach(code => {
|
| 975 |
+
code.closest('pre').classList.add('hidden');
|
| 976 |
+
});
|
| 977 |
+
|
| 978 |
+
// Activer l'onglet cliqué
|
| 979 |
+
e.target.classList.add('border-green-500', 'text-green-500', 'bg-gray-800');
|
| 980 |
+
e.target.classList.remove('border-transparent', 'text-gray-400-var', 'hover:text-white', 'hover:bg-gray-800');
|
| 981 |
+
|
| 982 |
+
// Afficher le bloc de code correspondant
|
| 983 |
+
const lang = e.target.getAttribute('data-lang');
|
| 984 |
+
document.getElementById('code-' + lang).closest('pre').classList.remove('hidden');
|
| 985 |
+
|
| 986 |
+
// Réinitialiser la coloration syntaxique
|
| 987 |
+
hljs.highlightAll();
|
| 988 |
+
}
|
| 989 |
+
});
|
| 990 |
+
</script>
|
| 991 |
+
</body>
|
| 992 |
+
</html>
|
templates/inscription.html
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Inscription - Nexus</title>
|
| 7 |
+
<link rel="stylesheet"
|
| 8 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 9 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 10 |
+
<style>
|
| 11 |
+
body { font-family: 'Inter', sans-serif; }
|
| 12 |
+
|
| 13 |
+
/* Transition pour un effet doux des couleurs */
|
| 14 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 15 |
+
|
| 16 |
+
/* Style et positionnement du bouton */
|
| 17 |
+
.theme-switch {
|
| 18 |
+
background: none;
|
| 19 |
+
border: none;
|
| 20 |
+
cursor: pointer;
|
| 21 |
+
font-size: 24px;
|
| 22 |
+
transition: color 0.2s;
|
| 23 |
+
position: absolute;
|
| 24 |
+
top: 1rem;
|
| 25 |
+
right: 1rem;
|
| 26 |
+
z-index: 10;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Définir les Variables de Thème */
|
| 30 |
+
/* Mode Sombre (Défaut : noir très foncé #121212) */
|
| 31 |
+
:root, .dark {
|
| 32 |
+
--bg-page: #121212;
|
| 33 |
+
--bg-card: #1E1E1E;
|
| 34 |
+
--text-color: #FFFFFF; /* Modifié pour blanc en mode sombre */
|
| 35 |
+
--input-bg: #2C2C2C;
|
| 36 |
+
--border-color: #383838;
|
| 37 |
+
--primary-color: #3B82F6;
|
| 38 |
+
--primary-hover: #2563EB;
|
| 39 |
+
--error-color: #DC2626;
|
| 40 |
+
}
|
| 41 |
+
/* Mode Clair */
|
| 42 |
+
.light {
|
| 43 |
+
--bg-page: #F5F5F5;
|
| 44 |
+
--bg-card: #FFFFFF;
|
| 45 |
+
--text-color: #000000; /* Modifié pour noir foncé en mode clair */
|
| 46 |
+
--input-bg: #FFFFFF;
|
| 47 |
+
--border-color: #D1D5DB;
|
| 48 |
+
--primary-color: #3B82F6;
|
| 49 |
+
--primary-hover: #2563EB;
|
| 50 |
+
--error-color: #DC2626;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Appliquer les variables au body et aux éléments */
|
| 54 |
+
.bg-page-var { background-color: var(--bg-page); }
|
| 55 |
+
.bg-card-var { background-color: var(--bg-card); }
|
| 56 |
+
.text-color-var { color: var(--text-color); }
|
| 57 |
+
.bg-input-var { background-color: var(--input-bg); }
|
| 58 |
+
.border-color-var { border-color: var(--border-color); }
|
| 59 |
+
.text-primary-color-var { color: var(--primary-color); }
|
| 60 |
+
.bg-primary-color-var { background-color: var(--primary-color); }
|
| 61 |
+
.hover\:text-primary-hover-var:hover { color: var(--primary-hover); }
|
| 62 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color); }
|
| 63 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color); }
|
| 64 |
+
|
| 65 |
+
/* MODIFICATION DEMANDÉE : Forcer le texte saisi dans les champs de formulaire en noir foncé (#000000) */
|
| 66 |
+
input[type="text"],
|
| 67 |
+
input[type="email"],
|
| 68 |
+
input[type="password"] {
|
| 69 |
+
color: #000000 !important;
|
| 70 |
+
}
|
| 71 |
+
</style>
|
| 72 |
+
</head>
|
| 73 |
+
<body class="bg-page-var transition-colors-theme min-h-screen flex items-center justify-center p-4">
|
| 74 |
+
|
| 75 |
+
<button id="theme-toggle" class="theme-switch text-color-var hover:text-primary-color-var transition-colors-theme">
|
| 76 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 77 |
+
</button>
|
| 78 |
+
|
| 79 |
+
<div class="w-full max-w-6xl flex flex-col md:flex-row shadow-2xl rounded-lg overflow-hidden">
|
| 80 |
+
|
| 81 |
+
<div class="hidden md:block md:w-1/2 bg-primary-color-var p-12 flex flex-col justify-center items-center text-white transition-colors-theme">
|
| 82 |
+
<svg class="w-32 h-32 mb-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
| 83 |
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 005.153 17.5a12.02 12.02 0 006.847 2.5a12.02 12.02 0 006.847-2.5 12.02 12.02 0 001.768-1.554z"></path>
|
| 84 |
+
</svg>
|
| 85 |
+
<h3 class="text-4xl font-extrabold mb-4 text-center">Rejoignez la Communauté Nexus</h3>
|
| 86 |
+
<p class="text-center text-lg">Créez votre compte pour accéder à l'intégralité de nos services et APIs.</p>
|
| 87 |
+
</div>
|
| 88 |
+
|
| 89 |
+
<div class="w-full md:w-1/2 bg-card-var transition-colors-theme p-8 md:p-12">
|
| 90 |
+
<h2 class="text-3xl font-bold text-center text-color-var mb-8 transition-colors-theme">Créer un Compte</h2>
|
| 91 |
+
|
| 92 |
+
<p id="message" class="text-center text-red-500 mb-4"></p>
|
| 93 |
+
|
| 94 |
+
<form id="registerForm">
|
| 95 |
+
<div class="flex flex-wrap -mx-2 mb-4">
|
| 96 |
+
<div class="w-full md:w-1/2 px-2 mb-4 md:mb-0">
|
| 97 |
+
<label for="username" class="block text-sm font-medium text-color-var">Nom d'utilisateur</label>
|
| 98 |
+
<input type="text" id="username" name="username" placeholder="Choisissez un nom" required
|
| 99 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme" style="color: var(--text-color);">
|
| 100 |
+
</div>
|
| 101 |
+
|
| 102 |
+
<div class="w-full md:w-1/2 px-2">
|
| 103 |
+
<label for="email" class="block text-sm font-medium text-color-var">Adresse Email</label>
|
| 104 |
+
<input type="email" id="email" name="email" placeholder="votre@email.com" required
|
| 105 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme" style="color: var(--text-color);">
|
| 106 |
+
</div>
|
| 107 |
+
</div>
|
| 108 |
+
|
| 109 |
+
<div class="flex flex-wrap -mx-2 mb-4">
|
| 110 |
+
<div class="w-full md:w-1/2 px-2 mb-4 md:mb-0">
|
| 111 |
+
<label for="password" class="block text-sm font-medium text-color-var">Mot de Passe</label>
|
| 112 |
+
<input type="password" id="password" name="password" placeholder="Min. 8 caractères" required
|
| 113 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme" style="color: var(--text-color);">
|
| 114 |
+
</div>
|
| 115 |
+
|
| 116 |
+
<div class="w-full md:w-1/2 px-2">
|
| 117 |
+
<label for="confirm_password" class="block text-sm font-medium text-color-var">Confirmer Mot de Passe</label>
|
| 118 |
+
<input type="password" id="confirm_password" name="confirm_password" placeholder="Répétez votre mot de passe" required
|
| 119 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme" style="color: var(--text-color);">
|
| 120 |
+
</div>
|
| 121 |
+
</div>
|
| 122 |
+
|
| 123 |
+
<div class="flex flex-wrap -mx-2 mb-6">
|
| 124 |
+
<div class="w-full md:w-1/2 px-2 mb-4 md:mb-0">
|
| 125 |
+
<label for="security_question" class="block text-sm font-medium text-color-var">Question Secrète</label>
|
| 126 |
+
<input type="text" id="security_question" name="security_question" placeholder="Ex: Premier animal de compagnie?" required
|
| 127 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme" style="color: var(--text-color);">
|
| 128 |
+
</div>
|
| 129 |
+
|
| 130 |
+
<div class="w-full md:w-1/2 px-2">
|
| 131 |
+
<label for="security_answer" class="block text-sm font-medium text-color-var">Réponse Secrète</label>
|
| 132 |
+
<input type="text" id="security_answer" name="security_answer" placeholder="Votre réponse" required
|
| 133 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme" style="color: var(--text-color);">
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
|
| 137 |
+
<button type="submit"
|
| 138 |
+
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-color-var hover:bg-primary-hover-var focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-color-var transition duration-150 ease-in-out">
|
| 139 |
+
S'inscrire
|
| 140 |
+
</button>
|
| 141 |
+
</form>
|
| 142 |
+
|
| 143 |
+
<div class="mt-6 text-center">
|
| 144 |
+
<p class="text-sm text-color-var transition-colors-theme">
|
| 145 |
+
Vous avez déjà un compte ?
|
| 146 |
+
<a href="/connexion" class="text-primary-color-var hover:text-primary-hover-var font-medium">
|
| 147 |
+
Connectez-vous ici
|
| 148 |
+
</a>
|
| 149 |
+
</p>
|
| 150 |
+
</div>
|
| 151 |
+
</div>
|
| 152 |
+
</div>
|
| 153 |
+
|
| 154 |
+
<script>
|
| 155 |
+
const form = document.getElementById('registerForm');
|
| 156 |
+
const message = document.getElementById('message');
|
| 157 |
+
|
| 158 |
+
form.addEventListener('submit', async (e) => {
|
| 159 |
+
e.preventDefault();
|
| 160 |
+
message.textContent = 'Inscription en cours...';
|
| 161 |
+
message.className = 'text-gray-500 mb-4';
|
| 162 |
+
|
| 163 |
+
const password = form.password.value;
|
| 164 |
+
const confirm_password = form.confirm_password.value;
|
| 165 |
+
|
| 166 |
+
if (password !== confirm_password) {
|
| 167 |
+
message.textContent = 'Erreur : Les mots de passe ne correspondent pas.';
|
| 168 |
+
message.className = 'text-red-500 mb-4';
|
| 169 |
+
return;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
const formData = {
|
| 173 |
+
username: form.username.value,
|
| 174 |
+
email: form.email.value,
|
| 175 |
+
password: password,
|
| 176 |
+
confirm_password: confirm_password,
|
| 177 |
+
security_question: form.security_question.value,
|
| 178 |
+
security_answer: form.security_answer.value
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
try {
|
| 182 |
+
const response = await fetch('/api/register', {
|
| 183 |
+
method: 'POST',
|
| 184 |
+
headers: { 'Content-Type': 'application/json' },
|
| 185 |
+
body: JSON.stringify(formData)
|
| 186 |
+
});
|
| 187 |
+
|
| 188 |
+
const data = await response.json();
|
| 189 |
+
|
| 190 |
+
if (data.status === 'Success') {
|
| 191 |
+
message.textContent = data.message + " Redirection vers le tableau de bord...";
|
| 192 |
+
message.className = 'text-green-500 mb-4';
|
| 193 |
+
// REDIRECTION AUTOMATIQUE VERS LE DASHBOARD
|
| 194 |
+
setTimeout(() => {
|
| 195 |
+
window.location.href = '/dashboard';
|
| 196 |
+
}, 1500);
|
| 197 |
+
} else {
|
| 198 |
+
message.textContent = 'Erreur : ' + (data.message || 'Échec de l\'inscription.');
|
| 199 |
+
message.className = 'text-red-500 mb-4';
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
} catch (error) {
|
| 203 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 204 |
+
message.textContent = 'Erreur de connexion au serveur.';
|
| 205 |
+
message.className = 'text-red-500 mb-4';
|
| 206 |
+
}
|
| 207 |
+
});
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
// Logique du thème (conservée pour l'esthétique)
|
| 211 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 212 |
+
const html = document.documentElement;
|
| 213 |
+
|
| 214 |
+
const updateIcon = () => {
|
| 215 |
+
const icon = themeToggle.querySelector('.material-symbols-rounded');
|
| 216 |
+
if (html.classList.contains('light')) {
|
| 217 |
+
icon.textContent = 'light_mode';
|
| 218 |
+
} else {
|
| 219 |
+
icon.textContent = 'dark_mode';
|
| 220 |
+
}
|
| 221 |
+
};
|
| 222 |
+
|
| 223 |
+
const savedTheme = localStorage.getItem('theme');
|
| 224 |
+
if (savedTheme === 'light') {
|
| 225 |
+
html.classList.remove('dark');
|
| 226 |
+
html.classList.add('light');
|
| 227 |
+
} else {
|
| 228 |
+
html.classList.add('dark');
|
| 229 |
+
html.classList.remove('light');
|
| 230 |
+
}
|
| 231 |
+
updateIcon();
|
| 232 |
+
|
| 233 |
+
themeToggle.addEventListener('click', () => {
|
| 234 |
+
if (html.classList.contains('dark')) {
|
| 235 |
+
html.classList.remove('dark');
|
| 236 |
+
html.classList.add('light');
|
| 237 |
+
localStorage.setItem('theme', 'light');
|
| 238 |
+
} else {
|
| 239 |
+
html.classList.remove('light');
|
| 240 |
+
html.classList.add('dark');
|
| 241 |
+
localStorage.setItem('theme', 'dark');
|
| 242 |
+
}
|
| 243 |
+
updateIcon();
|
| 244 |
+
});
|
| 245 |
+
</script>
|
| 246 |
+
</body>
|
| 247 |
+
</html>
|
templates/mentions_legales.html
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Mentions Légales - Nexus</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.21.0/tocbot.css">
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
body { font-family: 'Inter', sans-serif; }
|
| 13 |
+
/* Style pour les boutons carrés */
|
| 14 |
+
.btn-square {
|
| 15 |
+
border-radius: 0;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
/* Étape 2 : Définir les Styles (CSS) */
|
| 19 |
+
/* Variables Mode Sombre (Défaut) - Couleur noir très foncé demandée */
|
| 20 |
+
:root {
|
| 21 |
+
--bg-page: #0A0A0A; /* Noir très foncé */
|
| 22 |
+
--bg-main: #0A0A0A; /* Noir très foncé */
|
| 23 |
+
--bg-card: #121212; /* Arrière-plan des éléments (e.g., sidebar) */
|
| 24 |
+
--text-color-strong: #E3E3E3; /* White-like */
|
| 25 |
+
--text-color-main: #C0C0C0; /* Adjusted for content */
|
| 26 |
+
--text-muted: #9CA3AF; /* gray-400, for secondary text */
|
| 27 |
+
--border-color: #1F2937; /* gray-800, for borders */
|
| 28 |
+
--header-border: #3B82F6; /* blue-500/50, primary accent */
|
| 29 |
+
--toc-active-bg: #1F2937; /* Background for active TOC link (border-color) */
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
/* Variables Mode Clair */
|
| 33 |
+
html.light {
|
| 34 |
+
--bg-page: #F8F8F8;
|
| 35 |
+
--bg-main: #FFFFFF;
|
| 36 |
+
--bg-card: #F3F4F6;
|
| 37 |
+
--text-color-strong: #1F2937;
|
| 38 |
+
--text-color-main: #374151; /* gray-700 */
|
| 39 |
+
--text-muted: #6B7280; /* gray-500 */
|
| 40 |
+
--border-color: #E5E7EB;
|
| 41 |
+
--header-border: #10B981; /* teal-500/50 */
|
| 42 |
+
--toc-active-bg: #E5E7EB;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
/* Appliquer les variables aux sélecteurs principaux pour la couverture complète */
|
| 46 |
+
.bg-gray-900 { background-color: var(--bg-page) !important; }
|
| 47 |
+
.bg-gray-800\/50 { background-color: var(--bg-card) !important; }
|
| 48 |
+
.text-white { color: var(--text-color-strong) !important; }
|
| 49 |
+
.text-gray-300 { color: var(--text-color-main) !important; } /* Contenu principal */
|
| 50 |
+
.text-gray-400 { color: var(--text-muted) !important; }
|
| 51 |
+
.text-gray-500 { color: var(--text-muted) !important; } /* Texte footer */
|
| 52 |
+
.border-gray-700 { border-color: var(--border-color) !important; }
|
| 53 |
+
.border-gray-800 { border-color: var(--border-color) !important; }
|
| 54 |
+
.border-blue-500\/50 { border-color: var(--header-border) !important; }
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
/* Styles personnalisés pour intégrer Tocbot au thème sombre et "chat-like" */
|
| 58 |
+
.toc-list {
|
| 59 |
+
list-style: none;
|
| 60 |
+
padding-left: 0;
|
| 61 |
+
margin: 0;
|
| 62 |
+
}
|
| 63 |
+
.toc-list-item {
|
| 64 |
+
margin-bottom: 0.25rem;
|
| 65 |
+
}
|
| 66 |
+
.toc-list-item a {
|
| 67 |
+
display: block;
|
| 68 |
+
padding: 0.5rem 0.75rem;
|
| 69 |
+
color: var(--text-muted);
|
| 70 |
+
border-left: 2px solid transparent;
|
| 71 |
+
transition: all 0.2s;
|
| 72 |
+
font-size: 0.9rem;
|
| 73 |
+
}
|
| 74 |
+
.toc-list-item a:hover {
|
| 75 |
+
color: var(--text-color-strong);
|
| 76 |
+
border-left-color: #3B82F6;
|
| 77 |
+
}
|
| 78 |
+
.is-active-link {
|
| 79 |
+
font-weight: 700;
|
| 80 |
+
color: #3B82F6 !important;
|
| 81 |
+
border-left-color: #3B82F6 !important;
|
| 82 |
+
background-color: var(--toc-active-bg) !important; /* Utilisation de la variable */
|
| 83 |
+
border-radius: 0;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/* Style du bouton theme-switch (Étape 2) */
|
| 87 |
+
.theme-switch {
|
| 88 |
+
background: none;
|
| 89 |
+
border: none;
|
| 90 |
+
cursor: pointer;
|
| 91 |
+
color: var(--text-color-strong);
|
| 92 |
+
font-size: 28px; /* Rendu plus visible */
|
| 93 |
+
transition: color 0.2s;
|
| 94 |
+
margin-left: 1rem;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
/* Rendre la barre de navigation horizontale stable (sticky) */
|
| 98 |
+
.sticky-header {
|
| 99 |
+
position: sticky;
|
| 100 |
+
top: 0;
|
| 101 |
+
z-index: 50; /* Tailwind z-index: 50 */
|
| 102 |
+
background-color: var(--bg-page) !important; /* Assure la couleur de fond en mode sticky */
|
| 103 |
+
padding-top: 1rem;
|
| 104 |
+
padding-bottom: 1rem;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/* Rendre la barre latérale sticky et ajuster la hauteur max pour la rendre moins large verticalement */
|
| 108 |
+
/* lg:w-1/4 est conservé, mais style ajusté */
|
| 109 |
+
.lg\:h-screen {
|
| 110 |
+
height: auto; /* Supprimer la hauteur pleine écran */
|
| 111 |
+
max-height: calc(100vh - 8rem); /* Limiter la hauteur pour qu'elle soit moins large verticalement si nécessaire, tout en permettant le défilement */
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
@media (max-width: 1023px) {
|
| 115 |
+
.js-toc-container { display: none; }
|
| 116 |
+
}
|
| 117 |
+
</style>
|
| 118 |
+
</head>
|
| 119 |
+
<body class="bg-gray-900 text-white min-h-screen">
|
| 120 |
+
|
| 121 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 122 |
+
|
| 123 |
+
<header class="sticky-header flex flex-col sm:flex-row justify-between items-center border-b border-blue-500/50 mb-8">
|
| 124 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 125 |
+
NEXUS
|
| 126 |
+
</a>
|
| 127 |
+
<nav class="flex items-center space-x-4">
|
| 128 |
+
<a href="/support" class="px-6 py-3 bg-teal-600 text-white font-bold hover:bg-teal-700 transition duration-300 btn-square shadow-md">
|
| 129 |
+
Contacter l'Administration
|
| 130 |
+
</a>
|
| 131 |
+
|
| 132 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 133 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 134 |
+
</button>
|
| 135 |
+
</nav>
|
| 136 |
+
</header>
|
| 137 |
+
|
| 138 |
+
<main class="flex flex-col lg:flex-row lg:space-x-8">
|
| 139 |
+
|
| 140 |
+
<div class="lg:w-3/4 js-toc-content">
|
| 141 |
+
|
| 142 |
+
<h1 class="text-4xl font-extrabold text-white mb-6">
|
| 143 |
+
Mentions Légales
|
| 144 |
+
</h1>
|
| 145 |
+
<p class="text-gray-400 text-lg mb-10 border-l-4 border-blue-500 pl-4 italic">
|
| 146 |
+
Ces mentions légales définissent les obligations légales de la plateforme Nexus.
|
| 147 |
+
</p>
|
| 148 |
+
|
| 149 |
+
<h2 id="editeur" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 150 |
+
1. Informations sur l'Éditeur du Site
|
| 151 |
+
</h2>
|
| 152 |
+
<p class="text-gray-300 mb-6">
|
| 153 |
+
Le présent site et l'API sont édités par :
|
| 154 |
+
</p>
|
| 155 |
+
<ul class="list-disc list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 156 |
+
<li>Dénomination Sociale : [Nom de l'Entreprise / Nom Personnel]</li>
|
| 157 |
+
<li>Forme Juridique : [SARL / SAS / Entrepreneur Individuel, etc.]</li>
|
| 158 |
+
<li>Adresse du Siège Social : [Adresse complète, Pays]</li>
|
| 159 |
+
<li>Numéro d'immatriculation (RCS/SIRET) : [Numéro d'enregistrement légal]</li>
|
| 160 |
+
<li>Capital Social : [Montant du Capital, si applicable]</li>
|
| 161 |
+
<li>Adresse e-mail : contact@[votre-domaine].com</li>
|
| 162 |
+
<li>Numéro de téléphone : [Numéro de téléphone de contact]</li>
|
| 163 |
+
<li>Directeur de la publication : [Nom du Responsable Légal]</li>
|
| 164 |
+
</ul>
|
| 165 |
+
|
| 166 |
+
<h2 id="hebergement" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 167 |
+
2. Hébergement
|
| 168 |
+
</h2>
|
| 169 |
+
<p class="text-gray-300 mb-6">
|
| 170 |
+
L'hébergement du site web et de l'infrastructure API est assuré par :
|
| 171 |
+
</p>
|
| 172 |
+
<ul class="list-disc list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 173 |
+
<li>Nom de l'Hébergeur : Hugging Face</li>
|
| 174 |
+
<li>Adresse du Siège Social : [Adresse complète de l'Hébergeur]</li>
|
| 175 |
+
<li>Contact : https://academy.visiplus.com/blog/web-et-e-business/5-meilleurs-exemples-de-page-contact-pour-un-site-web-2018-07-23</li>
|
| 176 |
+
</ul>
|
| 177 |
+
|
| 178 |
+
<h2 id="propriete-intellectuelle" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 179 |
+
3. Propriété Intellectuelle
|
| 180 |
+
</h2>
|
| 181 |
+
<h3 id="droits-auteur" class="text-2xl font-semibold text-white mt-8 mb-3 pt-2">
|
| 182 |
+
3.1. Droits d'Auteur et Marques
|
| 183 |
+
</h3>
|
| 184 |
+
<p class="text-gray-300 mb-4">
|
| 185 |
+
L'ensemble des éléments constituant la Plateforme Nexus (structure, textes, images, sons, logiciels, logos, bases de données, y compris les interfaces API) sont la propriété exclusive de [Nom de l'Entreprise] ou sont utilisés avec l'autorisation de leurs titulaires, et sont protégés par le droit d'auteur.
|
| 186 |
+
</p>
|
| 187 |
+
<p class="text-gray-300 mb-6">
|
| 188 |
+
Toute reproduction, représentation, modification, publication, transmission ou dénaturation, totale ou partielle, du site ou de son contenu, par quelque procédé que ce soit, et sur quelque support que ce soit, est interdite. Les utilisateurs sont autorisés à utiliser l'API uniquement via la clé d'accès fournie et conformément aux Conditions d'Utilisation.
|
| 189 |
+
</p>
|
| 190 |
+
|
| 191 |
+
<h2 id="limitation-responsabilite" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 192 |
+
4. Limitation de Responsabilité
|
| 193 |
+
</h2>
|
| 194 |
+
<p class="text-gray-300 mb-6">
|
| 195 |
+
[Nom de l'Entreprise] s'efforce d'assurer au mieux de ses possibilités l'exactitude et la mise à jour des informations diffusées sur ce site, dont elle se réserve le droit de corriger, à tout moment et sans préavis, le contenu. Toutefois, l'Éditeur ne peut garantir l'exactitude, la précision ou l'exhaustivité des informations mises à disposition.
|
| 196 |
+
</p>
|
| 197 |
+
<ul class="list-disc list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 198 |
+
<li>Interruption de service : L'Éditeur n'est pas responsable des interruptions de service ou des dysfonctionnements techniques de l'API.</li>
|
| 199 |
+
<li>Sécurité : L'Utilisateur est seul responsable de la protection de sa clé API et des conséquences d'une éventuelle compromission.</li>
|
| 200 |
+
</ul>
|
| 201 |
+
|
| 202 |
+
<h2 id="donnees-personnelles-ml" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 203 |
+
5. Données Personnelles
|
| 204 |
+
</h2>
|
| 205 |
+
<p class="text-gray-300 mb-6">
|
| 206 |
+
Les informations relatives à la collecte et au traitement des données personnelles sont détaillées dans la Politique de Confidentialité de Nexus, accessible via le lien en bas de page.
|
| 207 |
+
</p>
|
| 208 |
+
|
| 209 |
+
<div class="mt-12 text-center">
|
| 210 |
+
<a href="/politique-confidentialite" class="px-6 py-3 bg-blue-600 text-white text-lg font-bold hover:bg-blue-700 transition duration-300 btn-square shadow-xl">
|
| 211 |
+
Voir la Politique de Confidentialité
|
| 212 |
+
</a>
|
| 213 |
+
</div>
|
| 214 |
+
|
| 215 |
+
</div>
|
| 216 |
+
|
| 217 |
+
<div class="lg:w-1/4 pt-4 sticky top-0 h-full lg:h-screen lg:overflow-y-auto js-toc-container">
|
| 218 |
+
<div class="lg:sticky lg:top-24 p-4 border border-gray-700 bg-gray-800/50">
|
| 219 |
+
<h3 class="text-xl font-semibold mb-4 text-blue-500">Navigation Rapide</h3>
|
| 220 |
+
<div class="js-toc"></div>
|
| 221 |
+
</div>
|
| 222 |
+
</div>
|
| 223 |
+
|
| 224 |
+
</main>
|
| 225 |
+
|
| 226 |
+
</div>
|
| 227 |
+
|
| 228 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.21.0/tocbot.min.js"></script>
|
| 229 |
+
<script>
|
| 230 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 231 |
+
tocbot.init({
|
| 232 |
+
tocSelector: '.js-toc',
|
| 233 |
+
contentSelector: '.js-toc-content',
|
| 234 |
+
headingSelector: 'h2, h3',
|
| 235 |
+
hasSmoothScroll: true,
|
| 236 |
+
headingsOffset: 60,
|
| 237 |
+
scrollSmoothOffset: -60,
|
| 238 |
+
});
|
| 239 |
+
});
|
| 240 |
+
</script>
|
| 241 |
+
|
| 242 |
+
<script>
|
| 243 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 244 |
+
const htmlElement = document.documentElement;
|
| 245 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 246 |
+
|
| 247 |
+
// Charger le thème depuis le localStorage
|
| 248 |
+
const savedTheme = localStorage.getItem('theme');
|
| 249 |
+
if (savedTheme === 'light') {
|
| 250 |
+
htmlElement.classList.add('light');
|
| 251 |
+
iconElement.textContent = 'dark_mode';
|
| 252 |
+
} else {
|
| 253 |
+
// S'assurer que le mode sombre est le défaut et que l'icône est correcte
|
| 254 |
+
htmlElement.classList.remove('light');
|
| 255 |
+
iconElement.textContent = 'light_mode';
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
themeToggle.addEventListener('click', () => {
|
| 259 |
+
if (htmlElement.classList.contains('light')) {
|
| 260 |
+
// Basculer vers le mode sombre
|
| 261 |
+
htmlElement.classList.remove('light');
|
| 262 |
+
localStorage.setItem('theme', 'dark');
|
| 263 |
+
iconElement.textContent = 'light_mode';
|
| 264 |
+
} else {
|
| 265 |
+
// Basculer vers le mode clair
|
| 266 |
+
htmlElement.classList.add('light');
|
| 267 |
+
localStorage.setItem('theme', 'light');
|
| 268 |
+
iconElement.textContent = 'dark_mode';
|
| 269 |
+
}
|
| 270 |
+
});
|
| 271 |
+
</script>
|
| 272 |
+
|
| 273 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900">
|
| 274 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 275 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 276 |
+
|
| 277 |
+
<div class="col-span-2 lg:col-span-1">
|
| 278 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 279 |
+
<p class="mt-3 text-gray-400">
|
| 280 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 281 |
+
</p>
|
| 282 |
+
<div class="mt-4 flex space-x-4">
|
| 283 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 284 |
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.014 4.85.07c3.275.146 4.47 1.583 4.61 4.85.056 1.266.07 1.646.07 4.85s-.014 3.584-.07 4.85c-.14 3.267-1.335 4.704-4.61 4.85-1.266.056-1.646.07-4.85.07s-3.584-.014-4.85-.07c-3.275-.146-4.47-1.583-4.61-4.85-.056-1.266-.07-1.646-.07-4.85s.014-3.584.07-4.85c.14-3.267 1.335-4.704 4.61-4.85 1.266-.056 1.646-.07 4.85-.07zM12 0c-3.784 0-4.285.016-5.773.083-4.722.211-6.755 2.24-6.965 6.965C.016 7.715 0 8.216 0 12s.016 4.285.083 5.773c.21 4.721 2.239 6.755 6.965 6.965 1.488.067 1.99.083 5.773.083s4.285-.016 5.773-.083c4.721-.21 6.755-2.239 6.965-6.965.067-1.488.083-1.99.083-5.773s-.016-4.285-.083-5.773c-.21-4.722-2.239-6.755-6.965-6.965C16.285.016 15.784 0 12 0zm0 14.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z"/></svg>
|
| 285 |
+
</a>
|
| 286 |
+
</div>
|
| 287 |
+
</div>
|
| 288 |
+
|
| 289 |
+
<div>
|
| 290 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 291 |
+
<ul class="space-y-3 text-gray-400">
|
| 292 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 293 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 294 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 295 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 296 |
+
</ul>
|
| 297 |
+
</div>
|
| 298 |
+
|
| 299 |
+
<div>
|
| 300 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 301 |
+
<ul class="space-y-3 text-gray-400">
|
| 302 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 303 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 304 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 305 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 306 |
+
</ul>
|
| 307 |
+
</div>
|
| 308 |
+
|
| 309 |
+
<div class="col-span-2 md:col-span-1">
|
| 310 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 311 |
+
<ul class="space-y-3 text-gray-400">
|
| 312 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 313 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 314 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 315 |
+
</ul>
|
| 316 |
+
</div>
|
| 317 |
+
|
| 318 |
+
</div>
|
| 319 |
+
|
| 320 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm">
|
| 321 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 322 |
+
</div>
|
| 323 |
+
</div>
|
| 324 |
+
</footer>
|
| 325 |
+
|
| 326 |
+
</body>
|
| 327 |
+
</html>
|
templates/mot_de_passe_oublie.html
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Récupération de Mot de Passe - Nexus</title>
|
| 7 |
+
<link rel="stylesheet"
|
| 8 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 9 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 10 |
+
<style>
|
| 11 |
+
body { font-family: 'Inter', sans-serif; }
|
| 12 |
+
|
| 13 |
+
/* Transition pour un effet doux des couleurs */
|
| 14 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 15 |
+
|
| 16 |
+
/* Style et positionnement du bouton */
|
| 17 |
+
.theme-switch {
|
| 18 |
+
background: none;
|
| 19 |
+
border: none;
|
| 20 |
+
cursor: pointer;
|
| 21 |
+
font-size: 24px;
|
| 22 |
+
transition: color 0.2s;
|
| 23 |
+
position: absolute;
|
| 24 |
+
top: 1rem;
|
| 25 |
+
right: 1rem;
|
| 26 |
+
z-index: 10;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* Définir les Variables de Thème (Harmonisé avec inscription.html) */
|
| 30 |
+
/* Mode Sombre (Défaut : noir très foncé #121212) */
|
| 31 |
+
:root, .dark {
|
| 32 |
+
--bg-page: #121212;
|
| 33 |
+
--bg-card: #1E1E1E;
|
| 34 |
+
--text-color: #FFFFFF; /* Texte général blanc en mode sombre */
|
| 35 |
+
--input-bg: #2C2C2C;
|
| 36 |
+
--border-color: #383838;
|
| 37 |
+
--primary-color: #3B82F6;
|
| 38 |
+
--primary-hover: #2563EB;
|
| 39 |
+
--error-color: #DC2626;
|
| 40 |
+
}
|
| 41 |
+
/* Mode Clair */
|
| 42 |
+
.light {
|
| 43 |
+
--bg-page: #F5F5F5;
|
| 44 |
+
--bg-card: #FFFFFF;
|
| 45 |
+
--text-color: #000000; /* Texte général noir foncé en mode clair */
|
| 46 |
+
--input-bg: #FFFFFF;
|
| 47 |
+
--border-color: #D1D5DB;
|
| 48 |
+
--primary-color: #3B82F6;
|
| 49 |
+
--primary-hover: #2563EB;
|
| 50 |
+
--error-color: #DC2626;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* Appliquer les variables au body et aux éléments */
|
| 54 |
+
.bg-page-var { background-color: var(--bg-page); }
|
| 55 |
+
.bg-card-var { background-color: var(--bg-card); }
|
| 56 |
+
.text-color-var { color: var(--text-color); }
|
| 57 |
+
.bg-input-var { background-color: var(--input-bg); }
|
| 58 |
+
.border-color-var { border-color: var(--border-color); }
|
| 59 |
+
.text-primary-color-var { color: var(--primary-color); }
|
| 60 |
+
.bg-primary-color-var { background-color: var(--primary-color); }
|
| 61 |
+
.hover\:text-primary-hover-var:hover { color: var(--primary-hover); }
|
| 62 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color); }
|
| 63 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color); }
|
| 64 |
+
|
| 65 |
+
/* Forcer le texte saisi dans les champs de formulaire en noir foncé (#000000) */
|
| 66 |
+
input[type="text"],
|
| 67 |
+
input[type="email"],
|
| 68 |
+
input[type="password"] {
|
| 69 |
+
color: #000000 !important;
|
| 70 |
+
}
|
| 71 |
+
</style>
|
| 72 |
+
</head>
|
| 73 |
+
<body class="bg-page-var transition-colors-theme min-h-screen flex items-center justify-center p-4">
|
| 74 |
+
|
| 75 |
+
<button id="theme-toggle" class="theme-switch text-color-var hover:text-primary-color-var transition-colors-theme">
|
| 76 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 77 |
+
</button>
|
| 78 |
+
|
| 79 |
+
<div class="w-full max-w-6xl flex flex-col md:flex-row shadow-2xl rounded-lg overflow-hidden">
|
| 80 |
+
|
| 81 |
+
<div class="hidden md:block md:w-1/2 bg-primary-color-var p-12 flex flex-col justify-center items-center text-white transition-colors-theme">
|
| 82 |
+
<span class="material-symbols-rounded w-32 h-32 mb-6" style="font-size: 8rem;">key</span>
|
| 83 |
+
<h3 class="text-4xl font-extrabold mb-4 text-center">Sécurité du Compte</h3>
|
| 84 |
+
<p class="text-center text-lg">Suivez les étapes pour réinitialiser et protéger votre mot de passe.</p>
|
| 85 |
+
</div>
|
| 86 |
+
|
| 87 |
+
<div class="w-full md:w-1/2 bg-card-var transition-colors-theme p-8 md:p-12">
|
| 88 |
+
<h2 class="text-3xl font-bold text-center text-color-var mb-3 transition-colors-theme">Récupérer le Compte</h2>
|
| 89 |
+
<p class="text-center text-color-var text-sm mb-6 transition-colors-theme">Réinitialisez votre mot de passe en répondant à votre question secrète.</p>
|
| 90 |
+
|
| 91 |
+
<p id="message" class="text-center text-red-500 mb-4"></p>
|
| 92 |
+
|
| 93 |
+
<form id="forgotPasswordForm">
|
| 94 |
+
<div class="mb-4">
|
| 95 |
+
<label for="username_or_email" class="block text-sm font-medium text-color-var">Nom d'utilisateur ou Email</label>
|
| 96 |
+
<input type="text" id="username_or_email" name="username_or_email" placeholder="Votre identifiant" required
|
| 97 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 98 |
+
</div>
|
| 99 |
+
|
| 100 |
+
<div class="mb-4">
|
| 101 |
+
<label for="security_answer" class="block text-sm font-medium text-color-var">Réponse à la Question Secrète</label>
|
| 102 |
+
<input type="text" id="security_answer" name="security_answer" placeholder="Votre réponse secrète" required
|
| 103 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 104 |
+
</div>
|
| 105 |
+
|
| 106 |
+
<div class="flex flex-wrap -mx-2 mb-4">
|
| 107 |
+
<div class="w-full md:w-1/2 px-2 mb-4 md:mb-0">
|
| 108 |
+
<label for="new_password" class="block text-sm font-medium text-color-var">Nouveau Mot de Passe</label>
|
| 109 |
+
<input type="password" id="new_password" name="new_password" placeholder="Votre nouveau mot de passe" required
|
| 110 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 111 |
+
</div>
|
| 112 |
+
|
| 113 |
+
<div class="w-full md:w-1/2 px-2">
|
| 114 |
+
<label for="confirm_new_password" class="block text-sm font-medium text-color-var">Confirmer Nouveau Mot de Passe</label>
|
| 115 |
+
<input type="password" id="confirm_new_password" name="confirm_new_password" placeholder="Répétez le nouveau mot de passe" required
|
| 116 |
+
class="mt-1 block w-full px-3 py-2 border border-border-color-var rounded-md shadow-sm bg-input-bg-var text-color-var focus:outline-none focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 117 |
+
</div>
|
| 118 |
+
</div>
|
| 119 |
+
|
| 120 |
+
<button type="submit"
|
| 121 |
+
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-color-var hover:bg-primary-hover-var focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-color-var transition duration-150 ease-in-out">
|
| 122 |
+
Réinitialiser et Se Connecter
|
| 123 |
+
</button>
|
| 124 |
+
</form>
|
| 125 |
+
|
| 126 |
+
<div class="mt-6 text-center">
|
| 127 |
+
<p class="text-sm text-color-var transition-colors-theme">
|
| 128 |
+
Vous vous souvenez de votre mot de passe ?
|
| 129 |
+
<a href="/connexion" class="text-primary-color-var hover:text-primary-hover-var font-medium">
|
| 130 |
+
Retour à la connexion
|
| 131 |
+
</a>
|
| 132 |
+
</p>
|
| 133 |
+
</div>
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
|
| 137 |
+
<script>
|
| 138 |
+
const form = document.getElementById('forgotPasswordForm');
|
| 139 |
+
const message = document.getElementById('message');
|
| 140 |
+
|
| 141 |
+
form.addEventListener('submit', async (e) => {
|
| 142 |
+
e.preventDefault();
|
| 143 |
+
message.textContent = 'Réinitialisation en cours...';
|
| 144 |
+
message.className = 'text-gray-500 mb-4';
|
| 145 |
+
|
| 146 |
+
const new_password = form.new_password.value;
|
| 147 |
+
const confirm_new_password = form.confirm_new_password.value;
|
| 148 |
+
|
| 149 |
+
if (new_password !== confirm_new_password) {
|
| 150 |
+
message.textContent = 'Erreur : Les nouveaux mots de passe ne correspondent pas.';
|
| 151 |
+
message.className = 'text-red-500 mb-4';
|
| 152 |
+
return;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
const formData = {
|
| 156 |
+
username_or_email: form.username_or_email.value,
|
| 157 |
+
security_answer: form.security_answer.value,
|
| 158 |
+
new_password: new_password,
|
| 159 |
+
// confirm_password n'est pas envoyé à l'API, seulement utilisé pour la vérification client
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
try {
|
| 163 |
+
const response = await fetch('/api/forgot-password', {
|
| 164 |
+
method: 'POST',
|
| 165 |
+
headers: { 'Content-Type': 'application/json' },
|
| 166 |
+
body: JSON.stringify(formData)
|
| 167 |
+
});
|
| 168 |
+
|
| 169 |
+
const data = await response.json();
|
| 170 |
+
|
| 171 |
+
if (data.status === 'Success') {
|
| 172 |
+
// Le backend Flask tente une auto-connexion.
|
| 173 |
+
// Si elle réussit, on redirige vers le dashboard.
|
| 174 |
+
if (data.message.includes('connexion automatique')) {
|
| 175 |
+
message.textContent = data.message + " Redirection vers le tableau de bord...";
|
| 176 |
+
message.className = 'text-green-500 mb-4';
|
| 177 |
+
setTimeout(() => {
|
| 178 |
+
window.location.href = '/dashboard';
|
| 179 |
+
}, 1500);
|
| 180 |
+
} else {
|
| 181 |
+
// Auto-connexion ratée (ou message générique de l'API)
|
| 182 |
+
message.textContent = data.message + " Redirection vers la page de connexion...";
|
| 183 |
+
message.className = 'text-green-500 mb-4';
|
| 184 |
+
setTimeout(() => {
|
| 185 |
+
window.location.href = '/connexion';
|
| 186 |
+
}, 1500);
|
| 187 |
+
}
|
| 188 |
+
} else {
|
| 189 |
+
message.textContent = 'Erreur : ' + (data.message || 'Échec de la réinitialisation.');
|
| 190 |
+
message.className = 'text-red-500 mb-4';
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
} catch (error) {
|
| 194 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 195 |
+
message.textContent = 'Erreur de connexion au serveur.';
|
| 196 |
+
message.className = 'text-red-500 mb-4';
|
| 197 |
+
}
|
| 198 |
+
});
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
// Logique du thème (conservée pour l'esthétique)
|
| 202 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 203 |
+
const html = document.documentElement;
|
| 204 |
+
|
| 205 |
+
const updateIcon = () => {
|
| 206 |
+
const icon = themeToggle.querySelector('.material-symbols-rounded');
|
| 207 |
+
if (html.classList.contains('light')) {
|
| 208 |
+
icon.textContent = 'light_mode';
|
| 209 |
+
} else {
|
| 210 |
+
icon.textContent = 'dark_mode';
|
| 211 |
+
}
|
| 212 |
+
};
|
| 213 |
+
|
| 214 |
+
const savedTheme = localStorage.getItem('theme');
|
| 215 |
+
if (savedTheme === 'light') {
|
| 216 |
+
html.classList.remove('dark');
|
| 217 |
+
html.classList.add('light');
|
| 218 |
+
} else {
|
| 219 |
+
html.classList.add('dark');
|
| 220 |
+
html.classList.remove('light');
|
| 221 |
+
}
|
| 222 |
+
updateIcon();
|
| 223 |
+
|
| 224 |
+
themeToggle.addEventListener('click', () => {
|
| 225 |
+
if (html.classList.contains('dark')) {
|
| 226 |
+
html.classList.remove('dark');
|
| 227 |
+
html.classList.add('light');
|
| 228 |
+
localStorage.setItem('theme', 'light');
|
| 229 |
+
} else {
|
| 230 |
+
html.classList.remove('light');
|
| 231 |
+
html.classList.add('dark');
|
| 232 |
+
localStorage.setItem('theme', 'dark');
|
| 233 |
+
}
|
| 234 |
+
updateIcon();
|
| 235 |
+
});
|
| 236 |
+
</script>
|
| 237 |
+
</body>
|
| 238 |
+
</html>
|
templates/nouveau_project.html
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Mailix | Créer un Nouveau Projet</title>
|
| 7 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
/* Configuration de la police Inter et réutilisation des styles du Dashboard */
|
| 13 |
+
body { font-family: 'Inter', sans-serif; }
|
| 14 |
+
|
| 15 |
+
/* Transition pour un effet doux des couleurs */
|
| 16 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 17 |
+
|
| 18 |
+
/* Style et positionnement du bouton de Thème */
|
| 19 |
+
.theme-switch {
|
| 20 |
+
background: none;
|
| 21 |
+
border: none;
|
| 22 |
+
cursor: pointer;
|
| 23 |
+
font-size: 24px;
|
| 24 |
+
transition: color 0.2s;
|
| 25 |
+
position: fixed;
|
| 26 |
+
top: 1rem;
|
| 27 |
+
right: 1rem;
|
| 28 |
+
z-index: 60;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Définir les Variables de Thème (RÉUTILISATION) */
|
| 32 |
+
:root, .dark {
|
| 33 |
+
--bg-page: #121212;
|
| 34 |
+
--bg-card: #1E1E1E;
|
| 35 |
+
--bg-sidebar: #1E1E1E;
|
| 36 |
+
--bg-sidebar-active: #2C2C2C;
|
| 37 |
+
--border-sidebar: #383838;
|
| 38 |
+
--text-color: #FFFFFF;
|
| 39 |
+
--text-secondary: #D1D5DB;
|
| 40 |
+
--text-link: #3B82F6;
|
| 41 |
+
--text-link-hover: #60A5FA;
|
| 42 |
+
--input-bg: #2C2C2C;
|
| 43 |
+
--input-border: #4B5563;
|
| 44 |
+
--input-text-key: #6EE7B7;
|
| 45 |
+
--primary-color: #3B82F6;
|
| 46 |
+
--primary-hover: #2563EB;
|
| 47 |
+
}
|
| 48 |
+
.light {
|
| 49 |
+
--bg-page: #F5F5F5;
|
| 50 |
+
--bg-card: #FFFFFF;
|
| 51 |
+
--bg-sidebar: #FFFFFF;
|
| 52 |
+
--bg-sidebar-active: #F3F4F6;
|
| 53 |
+
--border-sidebar: #D1D5DB;
|
| 54 |
+
--text-color: #000000;
|
| 55 |
+
--text-secondary: #4B5563;
|
| 56 |
+
--text-link: #1D4ED8;
|
| 57 |
+
--text-link-hover: #3B82F6;
|
| 58 |
+
--input-bg: #FFFFFF;
|
| 59 |
+
--input-border: #D1D5DB;
|
| 60 |
+
--input-text-key: #059669;
|
| 61 |
+
--primary-color: #3B82F6;
|
| 62 |
+
--primary-hover: #2563EB;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
/* Appliquer les variables au body et aux éléments */
|
| 66 |
+
.bg-page-var { background-color: var(--bg-page); }
|
| 67 |
+
.bg-card-var { background-color: var(--bg-card); }
|
| 68 |
+
.bg-sidebar-var { background-color: var(--bg-sidebar); }
|
| 69 |
+
.border-sidebar-var { border-color: var(--border-sidebar); }
|
| 70 |
+
.text-color-var { color: var(--text-color); }
|
| 71 |
+
.text-secondary-var { color: var(--text-secondary); }
|
| 72 |
+
.text-link-var { color: var(--text-link); }
|
| 73 |
+
.hover\:text-link-hover-var:hover { color: var(--text-link-hover); }
|
| 74 |
+
.bg-input-var { background-color: var(--input-bg); }
|
| 75 |
+
.border-input-var { border-color: var(--input-border); }
|
| 76 |
+
.text-input-key-var { color: var(--input-text-key); }
|
| 77 |
+
.bg-primary-color-var { background-color: var(--primary-color); }
|
| 78 |
+
.hover\:bg-primary-hover-var:hover { background-color: var(--primary-hover); }
|
| 79 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color); }
|
| 80 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color); }
|
| 81 |
+
.bg-sidebar-active-var { background-color: var(--bg-sidebar-active); }
|
| 82 |
+
|
| 83 |
+
/* Sidebar Gauche - Fixée et masquée sur mobile */
|
| 84 |
+
.sidebar {
|
| 85 |
+
transition: transform 0.3s ease-in-out;
|
| 86 |
+
position: fixed;
|
| 87 |
+
top: 0;
|
| 88 |
+
left: 0;
|
| 89 |
+
z-index: 30;
|
| 90 |
+
height: 100vh;
|
| 91 |
+
transform: translateX(-100%);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
.sidebar.open {
|
| 95 |
+
transform: translateX(0);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/* Sur les grands écrans (lg), la sidebar est statique et toujours visible */
|
| 99 |
+
@media (min-width: 1024px) {
|
| 100 |
+
.sidebar {
|
| 101 |
+
transform: translateX(0) !important;
|
| 102 |
+
position: sticky; /* Changer à sticky ou rester fixed si vous voulez la scrollbar du body */
|
| 103 |
+
}
|
| 104 |
+
.main-content {
|
| 105 |
+
margin-left: 256px; /* Décaler le contenu principal de la largeur de la sidebar */
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
</style>
|
| 110 |
+
</head>
|
| 111 |
+
|
| 112 |
+
<body class="bg-page-var text-color-var min-h-screen transition-colors-theme flex">
|
| 113 |
+
|
| 114 |
+
<button id="theme-toggle" class="theme-switch text-color-var hover:text-link-hover-var transition-colors-theme">
|
| 115 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 116 |
+
</button>
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
<aside id="sidebar-left" class="sidebar sidebar-left w-64 bg-sidebar-var border-r border-sidebar-var p-6 flex flex-col transition-colors-theme">
|
| 120 |
+
|
| 121 |
+
<div class="flex items-center mb-6 shrink-0">
|
| 122 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 123 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Mailix</span>
|
| 124 |
+
</div>
|
| 125 |
+
|
| 126 |
+
<div class="flex-grow overflow-y-auto pr-2" id="scrollable-nav-container">
|
| 127 |
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-secondary-var mb-2">Fichiers Ouverts</h3>
|
| 128 |
+
<nav id="file-explorer" class="space-y-1 pb-4 border-b border-sidebar-var/50 mb-4">
|
| 129 |
+
</nav>
|
| 130 |
+
|
| 131 |
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-secondary-var mb-2">Navigation</h3>
|
| 132 |
+
<nav class="space-y-3 pb-4">
|
| 133 |
+
<a href="{{ url_for('user_bp.dashboard') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 134 |
+
<span class="material-symbols-rounded">dashboard</span>
|
| 135 |
+
<span class="ml-3">Dashboard</span>
|
| 136 |
+
</a>
|
| 137 |
+
|
| 138 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 139 |
+
<span class="material-symbols-rounded">person</span>
|
| 140 |
+
<span class="ml-3">Profil</span>
|
| 141 |
+
</a>
|
| 142 |
+
<a href="/parametres" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 143 |
+
<span class="material-symbols-rounded">settings</span> <span class="ml-3">Paramètres</span>
|
| 144 |
+
</a>
|
| 145 |
+
|
| 146 |
+
<a href="/aide" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 147 |
+
<span class="material-symbols-rounded">help</span>
|
| 148 |
+
<span class="ml-3">Aide & Support</span>
|
| 149 |
+
</a>
|
| 150 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 151 |
+
<span class="material-symbols-rounded">person</span>
|
| 152 |
+
<span class="ml-3">Profil</span>
|
| 153 |
+
</a>
|
| 154 |
+
|
| 155 |
+
<a href="/statut" class="flex items-center p-3 bg-sidebar-active-var text-color-var rounded-lg transition duration-150 transition-colors-theme">
|
| 156 |
+
<span class="material-symbols-rounded">monitor_heart</span>
|
| 157 |
+
<span class="ml-3">Statut de l'API</span>
|
| 158 |
+
</a>
|
| 159 |
+
<a href="{{ url_for('user_bp.deconnexion') }}" id="logout-button-sidebar" class="flex items-center p-3 text-red-500 hover:text-red-400 hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 160 |
+
<span class="material-symbols-rounded">deconnexion</span>
|
| 161 |
+
<span class="ml-3">Déconnexion</span>
|
| 162 |
+
</a>
|
| 163 |
+
</nav>
|
| 164 |
+
</div>
|
| 165 |
+
|
| 166 |
+
<div class="mt-auto pt-4 text-xs text-secondary-var transition-colors-theme border-t border-sidebar-var/50 shrink-0">
|
| 167 |
+
<p>Connecté en tant que: <span class="font-semibold text-color-var transition-colors-theme">{{ user.email if user and user.email else 'Chargement...' }}</span></p>
|
| 168 |
+
<p>Plan: <span class="font-semibold text-color-var transition-colors-theme">{{ (user.plan | upper) if user and user.plan else 'GRATUIT' }}</span></p>
|
| 169 |
+
</div>
|
| 170 |
+
|
| 171 |
+
</aside>
|
| 172 |
+
|
| 173 |
+
<div id="main-content" class="main-content flex-1 p-8 transition-colors-theme">
|
| 174 |
+
|
| 175 |
+
<header class="lg:hidden flex justify-between items-center mb-8">
|
| 176 |
+
<button id="sidebar-left-toggle" class="p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme">
|
| 177 |
+
<span class="material-symbols-rounded text-color-var">menu</span>
|
| 178 |
+
</button>
|
| 179 |
+
<div class="flex items-center">
|
| 180 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 181 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Mailix</span>
|
| 182 |
+
</div>
|
| 183 |
+
<div class="w-8"></div>
|
| 184 |
+
</header>
|
| 185 |
+
|
| 186 |
+
<h1 class="text-3xl font-bold mb-2 text-color-var transition-colors-theme">Créer un Nouveau Projet</h1>
|
| 187 |
+
<p class="text-secondary-var mb-8 transition-colors-theme">Configurez les paramètres de base de votre projet avant de passer à l'éditeur.</p>
|
| 188 |
+
|
| 189 |
+
<div class="max-w-3xl bg-card-var p-8 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme">
|
| 190 |
+
|
| 191 |
+
<form id="new-project-form" action="/project/editor" method="GET">
|
| 192 |
+
|
| 193 |
+
<div class="mb-6">
|
| 194 |
+
<label for="project-name" class="block text-sm font-medium text-color-var mb-2 transition-colors-theme">
|
| 195 |
+
Nom du Projet <span class="text-red-500">*</span>
|
| 196 |
+
</label>
|
| 197 |
+
<input type="text" id="project-name" name="name" required
|
| 198 |
+
class="w-full p-3 rounded-lg border border-input-border-var bg-input-var text-color-var
|
| 199 |
+
focus:outline-none focus:ring-2 focus:ring-primary-color-var transition-colors-theme"
|
| 200 |
+
placeholder="Ex: API de Stockage de Données">
|
| 201 |
+
<p class="text-xs text-secondary-var mt-1">Choisissez un nom descriptif pour votre projet.</p>
|
| 202 |
+
</div>
|
| 203 |
+
|
| 204 |
+
<div class="mb-6">
|
| 205 |
+
<label class="block text-sm font-medium text-color-var mb-2 transition-colors-theme">
|
| 206 |
+
Visibilité
|
| 207 |
+
</label>
|
| 208 |
+
|
| 209 |
+
<div class="flex items-center space-x-4">
|
| 210 |
+
<span class="text-secondary-var font-medium flex items-center">
|
| 211 |
+
<span class="material-symbols-rounded text-lg mr-1">lock</span> Privé
|
| 212 |
+
</span>
|
| 213 |
+
|
| 214 |
+
<div class="relative inline-block w-12 mr-2 align-middle select-none transition duration-200 ease-in">
|
| 215 |
+
<input type="checkbox" name="visibility" id="toggle-visibility" value="public" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-input-border-var border-4 appearance-none cursor-pointer" />
|
| 216 |
+
<label for="toggle-visibility" class="toggle-label block overflow-hidden h-6 rounded-full bg-input-border-var cursor-pointer transition-colors duration-200 ease-in"></label>
|
| 217 |
+
</div>
|
| 218 |
+
<span class="text-primary-color-var font-medium flex items-center">
|
| 219 |
+
<span class="material-symbols-rounded text-lg mr-1">public</span> Public
|
| 220 |
+
</span>
|
| 221 |
+
</div>
|
| 222 |
+
|
| 223 |
+
<p class="text-xs text-secondary-var mt-1">
|
| 224 |
+
<span id="visibility-status-text" class="font-semibold text-color-var transition-colors-theme">Privé</span>
|
| 225 |
+
</p>
|
| 226 |
+
</div>
|
| 227 |
+
|
| 228 |
+
<div class="mb-8">
|
| 229 |
+
<label for="project-license" class="block text-sm font-medium text-color-var mb-2 transition-colors-theme">
|
| 230 |
+
Licence
|
| 231 |
+
</label>
|
| 232 |
+
<select id="project-license" name="license"
|
| 233 |
+
class="w-full p-3 rounded-lg border border-input-border-var bg-input-var text-color-var
|
| 234 |
+
focus:outline-none focus:ring-2 focus:ring-primary-color-var appearance-none transition-colors-theme">
|
| 235 |
+
<option value="none" class="bg-input-var text-color-var transition-colors-theme">Pas de licence (Droit d'auteur standard)</option>
|
| 236 |
+
<option value="MIT" class="bg-input-var text-color-var transition-colors-theme">MIT License (Très Permissive)</option>
|
| 237 |
+
<option value="Apache-2.0" class="bg-input-var text-color-var transition-colors-theme">Apache License 2.0</option>
|
| 238 |
+
<option value="GPL-3.0" class="bg-input-var text-color-var transition-colors-theme">GNU GPL v3.0 (Copyleft)</option>
|
| 239 |
+
<option value="CC0-1.0" class="bg-input-var text-color-var transition-colors-theme">CC0-1.0 (Domaine Public)</option>
|
| 240 |
+
</select>
|
| 241 |
+
<p class="text-xs text-secondary-var mt-1">
|
| 242 |
+
La licence que vous choisissez sera ajoutée automatiquement à votre projet.
|
| 243 |
+
</p>
|
| 244 |
+
</div>
|
| 245 |
+
|
| 246 |
+
<div class="flex justify-end">
|
| 247 |
+
<button type="submit"
|
| 248 |
+
class="px-6 py-3 bg-primary-color-var hover:bg-primary-hover-var text-white font-semibold rounded-lg shadow-md
|
| 249 |
+
transition duration-150 flex items-center">
|
| 250 |
+
Suivant : Configurer l'Éditeur
|
| 251 |
+
<span class="material-symbols-rounded ml-2">arrow_forward</span>
|
| 252 |
+
</button>
|
| 253 |
+
</div>
|
| 254 |
+
|
| 255 |
+
</form>
|
| 256 |
+
|
| 257 |
+
</div>
|
| 258 |
+
|
| 259 |
+
</div>
|
| 260 |
+
|
| 261 |
+
<script>
|
| 262 |
+
// --- LOGIQUE GÉNÉRALE (Thème et Sidebar) ---
|
| 263 |
+
|
| 264 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 265 |
+
const html = document.documentElement;
|
| 266 |
+
|
| 267 |
+
const updateIcon = () => {
|
| 268 |
+
const icon = themeToggle.querySelector('.material-symbols-rounded');
|
| 269 |
+
if (html.classList.contains('light')) {
|
| 270 |
+
icon.textContent = 'light_mode';
|
| 271 |
+
} else {
|
| 272 |
+
icon.textContent = 'dark_mode';
|
| 273 |
+
}
|
| 274 |
+
};
|
| 275 |
+
|
| 276 |
+
const savedTheme = localStorage.getItem('theme');
|
| 277 |
+
if (savedTheme === 'light') {
|
| 278 |
+
html.classList.remove('dark');
|
| 279 |
+
html.classList.add('light');
|
| 280 |
+
} else {
|
| 281 |
+
html.classList.add('dark');
|
| 282 |
+
html.classList.remove('light');
|
| 283 |
+
}
|
| 284 |
+
updateIcon();
|
| 285 |
+
|
| 286 |
+
themeToggle.addEventListener('click', () => {
|
| 287 |
+
if (html.classList.contains('dark')) {
|
| 288 |
+
html.classList.remove('dark');
|
| 289 |
+
html.classList.add('light');
|
| 290 |
+
localStorage.setItem('theme', 'light');
|
| 291 |
+
} else {
|
| 292 |
+
html.classList.remove('light');
|
| 293 |
+
html.classList.add('dark');
|
| 294 |
+
localStorage.setItem('theme', 'dark');
|
| 295 |
+
}
|
| 296 |
+
updateIcon();
|
| 297 |
+
});
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
// Logique pour la Sidebar Gauche sur mobile
|
| 301 |
+
const sidebarLeftToggle = document.getElementById('sidebar-left-toggle');
|
| 302 |
+
const sidebarLeft = document.getElementById('sidebar-left');
|
| 303 |
+
|
| 304 |
+
sidebarLeftToggle.addEventListener('click', () => {
|
| 305 |
+
sidebarLeft.classList.toggle('open');
|
| 306 |
+
});
|
| 307 |
+
|
| 308 |
+
// --- LOGIQUE SPÉCIFIQUE AU FORMULAIRE ---
|
| 309 |
+
|
| 310 |
+
// Logique de l'interrupteur Public/Privé
|
| 311 |
+
const visibilityToggle = document.getElementById('toggle-visibility');
|
| 312 |
+
const visibilityStatusText = document.getElementById('visibility-status-text');
|
| 313 |
+
|
| 314 |
+
// Styles pour l'interrupteur (tailwind ne supporte pas l'accès direct aux pseudo-éléments 'checked')
|
| 315 |
+
const updateToggleStyle = () => {
|
| 316 |
+
// Mise à jour de la couleur de fond de la piste de l'interrupteur (label)
|
| 317 |
+
const label = visibilityToggle.nextElementSibling;
|
| 318 |
+
|
| 319 |
+
if (visibilityToggle.checked) {
|
| 320 |
+
// Public (case cochée)
|
| 321 |
+
label.style.backgroundColor = 'var(--primary-color)';
|
| 322 |
+
visibilityStatusText.textContent = 'Public';
|
| 323 |
+
visibilityStatusText.classList.add('text-primary-color-var');
|
| 324 |
+
visibilityStatusText.classList.remove('text-warning-text-var'); // Si on avait un style d'alerte pour privé
|
| 325 |
+
} else {
|
| 326 |
+
// Privé (case non cochée)
|
| 327 |
+
label.style.backgroundColor = 'var(--input-border)';
|
| 328 |
+
visibilityStatusText.textContent = 'Privé';
|
| 329 |
+
visibilityStatusText.classList.remove('text-primary-color-var');
|
| 330 |
+
}
|
| 331 |
+
};
|
| 332 |
+
|
| 333 |
+
visibilityToggle.addEventListener('change', updateToggleStyle);
|
| 334 |
+
|
| 335 |
+
// Au chargement initial (par défaut, il est non coché -> Privé)
|
| 336 |
+
updateToggleStyle();
|
| 337 |
+
|
| 338 |
+
// Gestion du déplacement du bouton de l'interrupteur
|
| 339 |
+
// NOTE: Le style ci-dessous est nécessaire car Tailwind CSS ne gère pas directement le `:checked` + `+` (sibling) pour le style d'un toggle complex.
|
| 340 |
+
const style = document.createElement('style');
|
| 341 |
+
style.innerHTML = `
|
| 342 |
+
.toggle-checkbox:checked {
|
| 343 |
+
background-color: var(--primary-color);
|
| 344 |
+
}
|
| 345 |
+
.toggle-checkbox:checked + .toggle-label {
|
| 346 |
+
background-color: var(--primary-color);
|
| 347 |
+
}
|
| 348 |
+
.toggle-checkbox:checked + .toggle-label:before {
|
| 349 |
+
transform: translateX(100%);
|
| 350 |
+
}
|
| 351 |
+
.toggle-checkbox {
|
| 352 |
+
opacity: 0;
|
| 353 |
+
}
|
| 354 |
+
.toggle-label {
|
| 355 |
+
position: relative;
|
| 356 |
+
height: 24px;
|
| 357 |
+
width: 48px;
|
| 358 |
+
background-color: var(--input-border);
|
| 359 |
+
}
|
| 360 |
+
.toggle-label:before {
|
| 361 |
+
content: '';
|
| 362 |
+
position: absolute;
|
| 363 |
+
top: 2px;
|
| 364 |
+
left: 2px;
|
| 365 |
+
width: 20px;
|
| 366 |
+
height: 20px;
|
| 367 |
+
border-radius: 9999px;
|
| 368 |
+
background: white; /* Blanc pour le cercle, peu importe le thème */
|
| 369 |
+
transition: transform 0.2s ease-in-out;
|
| 370 |
+
}
|
| 371 |
+
`;
|
| 372 |
+
document.head.appendChild(style);
|
| 373 |
+
|
| 374 |
+
</script>
|
| 375 |
+
</body>
|
| 376 |
+
</html>
|
templates/politique_confidentialite.html
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Politique de Confidentialité - Nexus</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.21.0/tocbot.css">
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
body { font-family: 'Inter', sans-serif; }
|
| 13 |
+
|
| 14 |
+
/* Styles pour un noir très foncé et le mode clair */
|
| 15 |
+
/* Mode Sombre (Défaut, ajusté pour un noir très foncé) */
|
| 16 |
+
:root {
|
| 17 |
+
/* Couleurs par défaut (sombre) - Ajustées pour être plus noires que le gris/bleu de Tailwind */
|
| 18 |
+
--bg-page: #0A0A0A; /* Noir très foncé pour le fond principal */
|
| 19 |
+
--bg-card: #151515; /* Noir foncé pour les éléments/conteneurs */
|
| 20 |
+
--text-main: #E5E7EB; /* Gris très clair pour le texte principal (gray-200) */
|
| 21 |
+
--text-secondary: #9CA3AF; /* Gris moyen pour le texte secondaire (gray-400) */
|
| 22 |
+
--border-color: #374151; /* Gris foncé pour les bordures (gray-700) */
|
| 23 |
+
--blue-main: #3B82F6; /* Bleu Vif (blue-500) */
|
| 24 |
+
--blue-light: #60A5FA; /* Bleu Clair (blue-400) */
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/* Mode Clair */
|
| 28 |
+
html.light {
|
| 29 |
+
--bg-page: #F3F4F6; /* Gris très clair pour le fond principal (gray-100) */
|
| 30 |
+
--bg-card: #FFFFFF; /* Blanc pour les éléments/conteneurs */
|
| 31 |
+
--text-main: #1F2937; /* Gris très foncé pour le texte principal (gray-800) */
|
| 32 |
+
--text-secondary: #4B5563; /* Gris foncé pour le texte secondaire (gray-600) */
|
| 33 |
+
--border-color: #D1D5DB; /* Gris clair pour les bordures (gray-300) */
|
| 34 |
+
--blue-main: #2563EB; /* Bleu Vif (blue-600) */
|
| 35 |
+
--blue-light: #1D4ED8; /* Bleu Clair (blue-700) */
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/* Application des variables aux éléments de base */
|
| 39 |
+
body {
|
| 40 |
+
background-color: var(--bg-page);
|
| 41 |
+
color: var(--text-main);
|
| 42 |
+
transition: background-color 0.3s, color 0.3s;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
/* Remplacement des classes Tailwind par des variables CSS */
|
| 46 |
+
.bg-gray-900 { background-color: var(--bg-page) !important; }
|
| 47 |
+
.bg-gray-800\/50, .bg-gray-800 { background-color: var(--bg-card) !important; }
|
| 48 |
+
.text-white { color: var(--text-main) !important; }
|
| 49 |
+
.text-gray-400 { color: var(--text-secondary) !important; }
|
| 50 |
+
.text-gray-300 { color: var(--text-secondary) !important; }
|
| 51 |
+
.border-gray-700 { border-color: var(--border-color) !important; }
|
| 52 |
+
.border-gray-800 { border-color: var(--border-color) !important; }
|
| 53 |
+
.border-blue-500\/50 { border-color: var(--blue-main) !important; }
|
| 54 |
+
.text-blue-500 { color: var(--blue-main) !important; }
|
| 55 |
+
.text-blue-400 { color: var(--blue-light) !important; }
|
| 56 |
+
|
| 57 |
+
/* Style pour les boutons carrés */
|
| 58 |
+
.btn-square {
|
| 59 |
+
border-radius: 0; /* Supprime l'arrondi */
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/* Styles personnalisés pour intégrer Tocbot au thème "chat-like" */
|
| 63 |
+
.toc-list {
|
| 64 |
+
list-style: none;
|
| 65 |
+
padding-left: 0;
|
| 66 |
+
margin: 0;
|
| 67 |
+
}
|
| 68 |
+
.toc-list-item {
|
| 69 |
+
margin-bottom: 0.25rem;
|
| 70 |
+
}
|
| 71 |
+
.toc-list-item a {
|
| 72 |
+
display: block;
|
| 73 |
+
padding: 0.5rem 0.75rem;
|
| 74 |
+
color: var(--text-secondary); /* gray-400 */
|
| 75 |
+
border-left: 2px solid transparent;
|
| 76 |
+
transition: all 0.2s;
|
| 77 |
+
font-size: 0.9rem;
|
| 78 |
+
}
|
| 79 |
+
.toc-list-item a:hover {
|
| 80 |
+
color: var(--text-main); /* white */
|
| 81 |
+
border-left-color: var(--blue-main); /* blue-500 */
|
| 82 |
+
}
|
| 83 |
+
.is-active-link {
|
| 84 |
+
font-weight: 700;
|
| 85 |
+
color: var(--blue-main) !important; /* blue-500 */
|
| 86 |
+
border-left-color: var(--blue-main) !important;
|
| 87 |
+
background-color: var(--bg-card); /* gray-800 */
|
| 88 |
+
border-radius: 0; /* Style carré */
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
/* Style du bouton theme-switch (Étape 2) */
|
| 92 |
+
.theme-switch {
|
| 93 |
+
background: none;
|
| 94 |
+
border: none;
|
| 95 |
+
cursor: pointer;
|
| 96 |
+
color: var(--text-main);
|
| 97 |
+
font-size: 28px; /* Rendu légèrement plus grand */
|
| 98 |
+
transition: color 0.2s;
|
| 99 |
+
margin-left: 1rem;
|
| 100 |
+
}
|
| 101 |
+
.theme-switch:hover {
|
| 102 |
+
color: var(--blue-main);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
/* Fixer la barre latérale pour la rendre moins large (verticalement) et la cacher sur mobile */
|
| 106 |
+
/* Ajustement de la largeur de la barre latérale (lg:w-1/4 est conservé pour la structure) */
|
| 107 |
+
.lg\:w-1\/4 {
|
| 108 |
+
max-width: 300px; /* Limiter la largeur r��elle de la barre latérale sur grand écran */
|
| 109 |
+
width: 100%; /* S'assurer qu'il utilise l'espace disponible */
|
| 110 |
+
}
|
| 111 |
+
@media (max-width: 1023px) {
|
| 112 |
+
.js-toc-container { display: none; }
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
/* Ajustement pour l'en-tête fixe */
|
| 116 |
+
.header-fixed {
|
| 117 |
+
background-color: var(--bg-page);
|
| 118 |
+
z-index: 50;
|
| 119 |
+
padding-top: 1rem;
|
| 120 |
+
padding-bottom: 1rem;
|
| 121 |
+
}
|
| 122 |
+
</style>
|
| 123 |
+
</head>
|
| 124 |
+
<body class="min-h-screen">
|
| 125 |
+
|
| 126 |
+
<div class="max-w-7xl mx-auto p-4 sm:p-6 lg:p-8">
|
| 127 |
+
|
| 128 |
+
<header class="header-fixed fixed top-0 w-full flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8">
|
| 129 |
+
<div class="flex justify-between items-center w-full sm:w-auto">
|
| 130 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 131 |
+
NEXUS
|
| 132 |
+
</a>
|
| 133 |
+
<nav class="flex items-center space-x-4">
|
| 134 |
+
<a href="/support" class="px-6 py-3 bg-teal-600 text-white font-bold hover:bg-teal-700 transition duration-300 btn-square shadow-md">
|
| 135 |
+
Contacter le Support
|
| 136 |
+
</a>
|
| 137 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 138 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 139 |
+
</button>
|
| 140 |
+
</nav>
|
| 141 |
+
</div>
|
| 142 |
+
</header>
|
| 143 |
+
|
| 144 |
+
<div class="pt-28">
|
| 145 |
+
|
| 146 |
+
<main class="flex flex-col lg:flex-row lg:space-x-8">
|
| 147 |
+
|
| 148 |
+
<div class="lg:w-3/4 js-toc-content">
|
| 149 |
+
|
| 150 |
+
<h1 class="text-4xl font-extrabold text-white mb-6">
|
| 151 |
+
Politique de Confidentialité
|
| 152 |
+
</h1>
|
| 153 |
+
<p class="text-gray-400 text-lg mb-10 border-l-4 border-blue-500 pl-4 italic">
|
| 154 |
+
Dernière mise à jour : 15 Octobre 2024. Veuillez lire attentivement avant d'utiliser la plateforme Nexus.
|
| 155 |
+
</p>
|
| 156 |
+
|
| 157 |
+
<h2 id="champ-application" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 158 |
+
1. Champ d'Application
|
| 159 |
+
</h2>
|
| 160 |
+
<p class="text-gray-300 mb-6">
|
| 161 |
+
La présente Politique de Confidentialité régit la manière dont Nexus collecte, utilise, maintient et divulgue les informations collectées auprès des utilisateurs (chacun, un "Utilisateur") du site web, de l'application et de l'API Nexus (la "Plateforme"). Elle s'applique à la Plateforme et à tous les produits et services proposés par Nexus.
|
| 162 |
+
</p>
|
| 163 |
+
|
| 164 |
+
<h2 id="collecte-donnees" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 165 |
+
2. Collecte des Données Personnelles
|
| 166 |
+
</h2>
|
| 167 |
+
<p class="text-gray-300 mb-4">
|
| 168 |
+
Nous collectons des informations d'identification personnelle auprès des Utilisateurs de diverses manières, y compris, mais sans s'y limiter, lorsque les Utilisateurs visitent notre site, s'inscrivent sur la Plateforme, passent une commande d'API, remplissent un formulaire, et en relation avec d'autres activités, services, fonctionnalités ou ressources que nous mettons à disposition.
|
| 169 |
+
</p>
|
| 170 |
+
|
| 171 |
+
<h3 id="donnees-fournies" class="text-2xl font-semibold text-white mt-8 mb-3 pt-2">
|
| 172 |
+
2.1. Données que vous nous fournissez directement
|
| 173 |
+
</h3>
|
| 174 |
+
<ul class="list-disc list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 175 |
+
<li>Informations de Compte : Nom, adresse e-mail, mot de passe chiffré.</li>
|
| 176 |
+
<li>Informations de Facturation : Adresse de facturation, informations de paiement (traitées par un prestataire tiers sécurisé et non stockées par Nexus).</li>
|
| 177 |
+
<li>Communications : Enregistrements de correspondance lorsque vous contactez notre support.</li>
|
| 178 |
+
</ul>
|
| 179 |
+
|
| 180 |
+
<h3 id="donnees-automatiques" class="text-2xl font-semibold text-white mt-8 mb-3 pt-2">
|
| 181 |
+
2.2. Données collectées automatiquement (Logs API)
|
| 182 |
+
</h3>
|
| 183 |
+
<p class="text-gray-300 mb-6">
|
| 184 |
+
Lors de l'utilisation de notre API, nous enregistrons automatiquement des informations dans nos logs serveurs pour la sécurité, le dépannage et la facturation.
|
| 185 |
+
</p>
|
| 186 |
+
<ul class="list-disc list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 187 |
+
<li>Adresses IP des requêtes.</li>
|
| 188 |
+
<li>Horodatage, méthode et statut de l'appel API.</li>
|
| 189 |
+
<li>Erreurs et avertissements générés.</li>
|
| 190 |
+
<li>Clé API partiellement masquée (pour l'identification du compte).</li>
|
| 191 |
+
</ul>
|
| 192 |
+
|
| 193 |
+
<h2 id="utilisation-donnees" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 194 |
+
3. Comment nous utilisons les informations collectées
|
| 195 |
+
</h2>
|
| 196 |
+
<p class="text-gray-300 mb-4">
|
| 197 |
+
Nexus utilise les données collectées aux fins suivantes :
|
| 198 |
+
</p>
|
| 199 |
+
<ul class="list-decimal list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 200 |
+
<li>Pour fournir et maintenir le service : Assurer le bon fonctionnement de l'API et du Dashboard.</li>
|
| 201 |
+
<li>Pour la facturation : Calculer et traiter les frais d'utilisation de l'API.</li>
|
| 202 |
+
<li>Pour la sécurité : Détecter et prévenir les fraudes et les abus.</li>
|
| 203 |
+
<li>Pour l'amélioration : Améliorer nos produits et services API en fonction des données d'utilisation agrégées.</li>
|
| 204 |
+
<li>Pour la communication : Envoyer des notifications de service importantes et des informations de sécurité.</li>
|
| 205 |
+
</ul>
|
| 206 |
+
|
| 207 |
+
<h2 id="protection-donnees" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 208 |
+
4. Protection et Partage des Données
|
| 209 |
+
</h2>
|
| 210 |
+
<h3 id="mesures-securite" class="text-2xl font-semibold text-white mt-8 mb-3 pt-2">
|
| 211 |
+
4.1. Mesures de Sécurité
|
| 212 |
+
</h3>
|
| 213 |
+
<p class="text-gray-300 mb-6">
|
| 214 |
+
Nous adoptons des pratiques de collecte, de stockage et de traitement des données et des mesures de sécurité appropriées pour protéger contre l'accès non autorisé, la modification, la divulgation ou la destruction de vos informations personnelles et des données stockées sur notre Plateforme. Les informations sensibles et privées sont échangées via un canal de communication sécurisé SSL et sont chiffrées.
|
| 215 |
+
</p>
|
| 216 |
+
|
| 217 |
+
<h3 id="partage-tiers" class="text-2xl font-semibold text-white mt-8 mb-3 pt-2">
|
| 218 |
+
4.2. Partage avec des Tiers
|
| 219 |
+
</h3>
|
| 220 |
+
<p class="text-gray-300 mb-6">
|
| 221 |
+
Nous ne vendons, n'échangeons ni ne louons les informations d'identification personnelle des Utilisateurs à des tiers. Nous pouvons partager des informations démographiques agrégées et génériques non liées à des informations d'identification personnelle concernant les visiteurs et les Utilisateurs avec nos partenaires commerciaux, affiliés de confiance et annonceurs à des fins de marketing. Nous utilisons des fournisseurs de services tiers pour nous aider à exploiter notre activité (ex: traitement des paiements), mais ils sont contractuellement obligés de garder vos informations confidentielles.
|
| 222 |
+
</p>
|
| 223 |
+
|
| 224 |
+
<h2 id="droits-utilisateur" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 225 |
+
5. Droits des Utilisateurs (RGPD et autres)
|
| 226 |
+
</h2>
|
| 227 |
+
<p class="text-gray-300 mb-6">
|
| 228 |
+
Conformément aux réglementations applicables (comme le RGPD), vous disposez de droits concernant vos données personnelles :
|
| 229 |
+
</p>
|
| 230 |
+
<ul class="list-disc list-inside text-gray-300 space-y-2 ml-4 mb-6">
|
| 231 |
+
<li>Droit d'accès : Demander une copie des données que nous détenons sur vous.</li>
|
| 232 |
+
<li>Droit de rectification : Demander la correction de données inexactes.</li>
|
| 233 |
+
<li>Droit à l'oubli : Demander la suppression de vos données dans certaines conditions.</li>
|
| 234 |
+
<li>Droit à la limitation : Demander la limitation du traitement.</li>
|
| 235 |
+
</ul>
|
| 236 |
+
<p class="text-gray-300 mb-6">
|
| 237 |
+
Pour exercer l'un de ces droits, veuillez nous contacter via notre page de support. Nous répondrons à votre demande dans un délai légal.
|
| 238 |
+
</p>
|
| 239 |
+
|
| 240 |
+
<h2 id="modifications-politique" class="text-3xl font-bold text-blue-400 mt-10 mb-4 pt-2">
|
| 241 |
+
6. Modifications de cette politique
|
| 242 |
+
</h2>
|
| 243 |
+
<p class="text-gray-300 mb-6">
|
| 244 |
+
Nexus a la discrétion de mettre à jour cette politique de confidentialité à tout moment. Lorsque nous le ferons, nous réviserons la date de "Dernière mise à jour" au début de cette page. Nous encourageons les Utilisateurs à consulter fréquemment cette page pour tout changement. Vous reconnaissez et acceptez qu'il est de votre responsabilité de consulter périodiquement cette politique de confidentialité et de prendre connaissance des modifications.
|
| 245 |
+
</p>
|
| 246 |
+
|
| 247 |
+
<div class="mt-12 text-center">
|
| 248 |
+
<a href="/" class="px-6 py-3 bg-blue-600 text-white text-lg font-bold hover:bg-blue-700 transition duration-300 btn-square shadow-xl">
|
| 249 |
+
Retour à l'Accueil
|
| 250 |
+
</a>
|
| 251 |
+
</div>
|
| 252 |
+
|
| 253 |
+
</div>
|
| 254 |
+
|
| 255 |
+
<div class="lg:w-1/4 pt-4 sticky top-0 h-full lg:h-screen lg:overflow-y-auto js-toc-container">
|
| 256 |
+
<div class="lg:sticky lg:top-24 p-4 border border-gray-700 bg-gray-800/50">
|
| 257 |
+
<h3 class="text-xl font-semibold mb-4 text-blue-500">Navigation Rapide</h3>
|
| 258 |
+
<div class="js-toc"></div>
|
| 259 |
+
</div>
|
| 260 |
+
</div>
|
| 261 |
+
|
| 262 |
+
</main>
|
| 263 |
+
|
| 264 |
+
</div>
|
| 265 |
+
|
| 266 |
+
</div>
|
| 267 |
+
|
| 268 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.21.0/tocbot.min.js"></script>
|
| 269 |
+
<script>
|
| 270 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 271 |
+
tocbot.init({
|
| 272 |
+
tocSelector: '.js-toc',
|
| 273 |
+
contentSelector: '.js-toc-content',
|
| 274 |
+
headingSelector: 'h2, h3',
|
| 275 |
+
hasSmoothScroll: true,
|
| 276 |
+
headingsOffset: 120, // Ajusté pour le header fixe
|
| 277 |
+
scrollSmoothOffset: -120, // Ajusté pour le header fixe
|
| 278 |
+
});
|
| 279 |
+
});
|
| 280 |
+
|
| 281 |
+
// Étape 3 : Logique de bascule du mode sombre/clair
|
| 282 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 283 |
+
const htmlElement = document.documentElement;
|
| 284 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 285 |
+
|
| 286 |
+
// Charger le thème depuis le localStorage
|
| 287 |
+
const savedTheme = localStorage.getItem('theme');
|
| 288 |
+
if (savedTheme === 'light') {
|
| 289 |
+
htmlElement.classList.add('light');
|
| 290 |
+
iconElement.textContent = 'dark_mode'; // Afficher l'icône sombre
|
| 291 |
+
} else {
|
| 292 |
+
// Thème sombre par défaut
|
| 293 |
+
iconElement.textContent = 'light_mode'; // Afficher l'icône claire
|
| 294 |
+
if (!savedTheme) {
|
| 295 |
+
// S'assurer que le mode sombre est appliqué au chargement si aucun thème n'est sauvegardé
|
| 296 |
+
htmlElement.classList.remove('light');
|
| 297 |
+
localStorage.setItem('theme', 'dark');
|
| 298 |
+
}
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
themeToggle.addEventListener('click', () => {
|
| 302 |
+
if (htmlElement.classList.contains('light')) {
|
| 303 |
+
// Passer au mode sombre
|
| 304 |
+
htmlElement.classList.remove('light');
|
| 305 |
+
localStorage.setItem('theme', 'dark');
|
| 306 |
+
iconElement.textContent = 'light_mode'; // Afficher l'icône claire
|
| 307 |
+
} else {
|
| 308 |
+
// Passer au mode clair
|
| 309 |
+
htmlElement.classList.add('light');
|
| 310 |
+
localStorage.setItem('theme', 'light');
|
| 311 |
+
iconElement.textContent = 'dark_mode'; // Afficher l'icône sombre
|
| 312 |
+
}
|
| 313 |
+
});
|
| 314 |
+
</script>
|
| 315 |
+
|
| 316 |
+
<footer class="mt-16 border-t border-gray-700">
|
| 317 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 318 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 319 |
+
|
| 320 |
+
<div class="col-span-2 lg:col-span-1">
|
| 321 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 322 |
+
<p class="mt-3 text-gray-400">
|
| 323 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 324 |
+
</p>
|
| 325 |
+
<div class="mt-4 flex space-x-4">
|
| 326 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 327 |
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.014 4.85.07c3.275.146 4.47 1.583 4.61 4.85.056 1.266.07 1.646.07 4.85s-.014 3.584-.07 4.85c-.14 3.267-1.335 4.704-4.61 4.85-1.266.056-1.646.07-4.85.07s-3.584-.014-4.85-.07c-3.275-.146-4.47-1.583-4.61-4.85-.056-1.266-.07-1.646-.07-4.85s.014-3.584.07-4.85c.14-3.267 1.335-4.704 4.61-4.85 1.266-.056 1.646-.07 4.85-.07zM12 0c-3.784 0-4.285.016-5.773.083-4.722.211-6.755 2.24-6.965 6.965C.016 7.715 0 8.216 0 12s.016 4.285.083 5.773c.21 4.721 2.239 6.755 6.965 6.965 1.488.067 1.99.083 5.773.083s4.285-.016 5.773-.083c4.721-.21 6.755-2.239 6.965-6.965.067-1.488.083-1.99.083-5.773s-.016-4.285-.083-5.773c-.21-4.722-2.239-6.755-6.965-6.965C16.285.016 15.784 0 12 0zm0 14.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z"/></svg>
|
| 328 |
+
</a>
|
| 329 |
+
</div>
|
| 330 |
+
</div>
|
| 331 |
+
|
| 332 |
+
<div>
|
| 333 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 334 |
+
<ul class="space-y-3 text-gray-400">
|
| 335 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 336 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 337 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 338 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 339 |
+
</ul>
|
| 340 |
+
</div>
|
| 341 |
+
|
| 342 |
+
<div>
|
| 343 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 344 |
+
<ul class="space-y-3 text-gray-400">
|
| 345 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 346 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 347 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 348 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 349 |
+
</ul>
|
| 350 |
+
</div>
|
| 351 |
+
|
| 352 |
+
<div class="col-span-2 md:col-span-1">
|
| 353 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 354 |
+
<ul class="space-y-3 text-gray-400">
|
| 355 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 356 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 357 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 358 |
+
</ul>
|
| 359 |
+
</div>
|
| 360 |
+
|
| 361 |
+
</div>
|
| 362 |
+
|
| 363 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm">
|
| 364 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 365 |
+
</div>
|
| 366 |
+
</div>
|
| 367 |
+
</footer>
|
| 368 |
+
|
| 369 |
+
</body>
|
| 370 |
+
</html>
|
templates/profile.html
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Nexus | Profil Utilisateur - Pro</title>
|
| 7 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
/* Configuration de la police Inter */
|
| 13 |
+
body { font-family: 'Inter', sans-serif; }
|
| 14 |
+
|
| 15 |
+
/* Définition des variables de thème (Ajoutées pour le style) */
|
| 16 |
+
:root {
|
| 17 |
+
/* Couleurs de base (exemple - ajustez si nécessaire) */
|
| 18 |
+
--page-var: #f8fafc; /* light - slate-50 */
|
| 19 |
+
--color-var: #0f172a; /* light - slate-900 */
|
| 20 |
+
--secondary-var: #64748b; /* light - slate-500 */
|
| 21 |
+
--card-var: #ffffff; /* light - white */
|
| 22 |
+
--sidebar-var: #e2e8f0; /* light - slate-200 */
|
| 23 |
+
--sidebar-active-var: #cbd5e1; /* light - slate-300 */
|
| 24 |
+
--input-var: #f1f5f9; /* light - slate-100 */
|
| 25 |
+
--primary-color-var: #4f46e5; /* indigo-600 */
|
| 26 |
+
--primary-hover-var: #4338ca; /* indigo-700 */
|
| 27 |
+
--error-var: #fef2f2; /* red-50 */
|
| 28 |
+
--success-var: #f0fdf4; /* green-50 */
|
| 29 |
+
--warning-var: #fcd34d; /* amber-400 */
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
.dark {
|
| 33 |
+
--page-var: #18181b; /* dark - zinc-900 (Gris très foncé pour l'arrière-plan de la page) */
|
| 34 |
+
--color-var: #f4f4f5; /* dark - zinc-100 (Texte clair) */
|
| 35 |
+
--secondary-var: #a1a1aa; /* dark - zinc-400 (Texte secondaire) */
|
| 36 |
+
--card-var: #27272a; /* dark - zinc-800 (Gris foncé pour les cartes et la sidebar) */
|
| 37 |
+
--sidebar-var: #27272a; /* dark - zinc-800 */
|
| 38 |
+
--sidebar-active-var: #3f3f46; /* dark - zinc-700 (Gris un peu plus clair pour l'actif) */
|
| 39 |
+
--input-var: #18181b; /* dark - zinc-900 (Fond de champ de saisie) */
|
| 40 |
+
--primary-color-var: #6366f1; /* indigo-500 (Couleur primaire inchangée) */
|
| 41 |
+
--primary-hover-var: #4f46e5; /* indigo-600 */
|
| 42 |
+
--error-var: #450a0a; /* red-950 */
|
| 43 |
+
--success-var: #052e16; /* green-950 */
|
| 44 |
+
--warning-var: #b45309; /* amber-800 */
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/* Transition pour un effet doux des couleurs */
|
| 48 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 49 |
+
|
| 50 |
+
/* Style et positionnement du bouton de Thème */
|
| 51 |
+
.theme-switch {
|
| 52 |
+
background: none;
|
| 53 |
+
border: none;
|
| 54 |
+
cursor: pointer;
|
| 55 |
+
font-size: 24px;
|
| 56 |
+
transition: color 0.2s;
|
| 57 |
+
position: fixed; /* Reste fixe même si le reste défile */
|
| 58 |
+
top: 1rem;
|
| 59 |
+
right: 1rem;
|
| 60 |
+
z-index: 50; /* Doit être au-dessus du reste */
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/* Style pour la sidebar responsive */
|
| 64 |
+
.sidebar {
|
| 65 |
+
position: fixed;
|
| 66 |
+
top: 0;
|
| 67 |
+
left: 0;
|
| 68 |
+
height: 100vh;
|
| 69 |
+
z-index: 40;
|
| 70 |
+
transform: translateX(-100%);
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
/* Styles pour le mode desktop/large screen */
|
| 74 |
+
@media (min-width: 1024px) {
|
| 75 |
+
.sidebar {
|
| 76 |
+
transform: translateX(0);
|
| 77 |
+
}
|
| 78 |
+
.main-content {
|
| 79 |
+
margin-left: 16rem; /* 64px width */
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
/* Styles pour le mode mobile/tablet */
|
| 84 |
+
@media (max-width: 1023px) {
|
| 85 |
+
.sidebar {
|
| 86 |
+
transition: transform 0.3s ease-in-out;
|
| 87 |
+
}
|
| 88 |
+
.sidebar.open {
|
| 89 |
+
transform: translateX(0);
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
/* Ajout des styles pour les variables CSS dans Tailwind */
|
| 94 |
+
.bg-page-var { background-color: var(--page-var); }
|
| 95 |
+
.text-color-var { color: var(--color-var); }
|
| 96 |
+
.text-secondary-var { color: var(--secondary-var); }
|
| 97 |
+
.bg-card-var { background-color: var(--card-var); }
|
| 98 |
+
.bg-sidebar-var { background-color: var(--sidebar-var); }
|
| 99 |
+
.border-sidebar-var { border-color: var(--sidebar-var); }
|
| 100 |
+
.bg-sidebar-active-var { background-color: var(--sidebar-active-var); }
|
| 101 |
+
.bg-input-var { background-color: var(--input-var); }
|
| 102 |
+
.border-input-var { border-color: var(--input-var); }
|
| 103 |
+
.text-primary-color-var { color: var(--primary-color-var); }
|
| 104 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color-var); }
|
| 105 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color-var); }
|
| 106 |
+
.bg-primary-color-var { background-color: var(--primary-color-var); }
|
| 107 |
+
.hover\:bg-primary-hover-var:hover { background-color: var(--primary-hover-var); }
|
| 108 |
+
.hover\:bg-sidebar-active-var:hover { background-color: var(--sidebar-active-var); }
|
| 109 |
+
.hover\:bg-sidebar-active-var\/80:hover { background-color: color-mix(in srgb, var(--sidebar-active-var) 80%, transparent); }
|
| 110 |
+
|
| 111 |
+
/* Correction pour les messages flash pour utiliser les variables */
|
| 112 |
+
.bg-red-900\/20 { background-color: color-mix(in srgb, var(--error-var) 20%, transparent); } /* Approximation des couleurs spécifiques */
|
| 113 |
+
.text-red-500 { color: #ef4444; } /* Laissez le rouge spécifique pour les erreurs */
|
| 114 |
+
.border-red-900 { border-color: #7f1d1d; } /* Laissez le rouge spécifique pour les erreurs */
|
| 115 |
+
.bg-green-900\/20 { background-color: color-mix(in srgb, var(--success-var) 20%, transparent); } /* Approximation des couleurs spécifiques */
|
| 116 |
+
.text-green-500 { color: #22c55e; } /* Laissez le vert spécifique pour le succès */
|
| 117 |
+
.border-green-900 { border-color: #064e3b; } /* Laissez le vert spécifique pour le succès */
|
| 118 |
+
.hover\:text-link-hover-var:hover { color: var(--secondary-var); } /* Ajout d'une pseudo-variable pour le hover de l'icône de thème (simple fallback) */
|
| 119 |
+
|
| 120 |
+
</style>
|
| 121 |
+
</head>
|
| 122 |
+
|
| 123 |
+
<body class="bg-page-var text-color-var min-h-screen transition-colors-theme">
|
| 124 |
+
|
| 125 |
+
<button id="theme-switch" class="theme-switch text-color-var hover:text-link-hover-var transition-colors-theme">
|
| 126 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 127 |
+
</button>
|
| 128 |
+
|
| 129 |
+
<aside id="sidebar" class="sidebar w-64 bg-sidebar-var border-r border-sidebar-var p-6 lg:block transition-colors-theme">
|
| 130 |
+
<div class="flex items-center mb-10">
|
| 131 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 132 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Nexus Pro</span>
|
| 133 |
+
</div>
|
| 134 |
+
|
| 135 |
+
<nav class="space-y-3">
|
| 136 |
+
<a href="{{ url_for('user_bp.dashboard') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 137 |
+
<span class="material-symbols-rounded">dashboard</span>
|
| 138 |
+
<span class="ml-3">Dashboard</span>
|
| 139 |
+
</a>
|
| 140 |
+
<a href="{{ url_for('user_bp.api_key') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 141 |
+
<span class="material-symbols-rounded">key</span>
|
| 142 |
+
<span class="ml-3">Clés API</span>
|
| 143 |
+
</a>
|
| 144 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 bg-sidebar-active-var text-color-var rounded-lg transition duration-150 transition-colors-theme">
|
| 145 |
+
<span class="material-symbols-rounded">person</span>
|
| 146 |
+
<span class="ml-3">Profil</span>
|
| 147 |
+
</a>
|
| 148 |
+
<a href="/api_logs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 149 |
+
<span class="material-symbols-rounded">list_alt</span>
|
| 150 |
+
<span class="ml-3">Logs d'API</span>
|
| 151 |
+
</a>
|
| 152 |
+
<a href="/tarifs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 153 |
+
<span class="material-symbols-rounded">payments</span>
|
| 154 |
+
<span class="ml-3">Tarifs</span>
|
| 155 |
+
</a>
|
| 156 |
+
<a href="/statut" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 157 |
+
<span class="material-symbols-rounded">monitor_heart</span>
|
| 158 |
+
<span class="ml-3">Statut de l'API</span>
|
| 159 |
+
</a>
|
| 160 |
+
<a href="{{ url_for('user_bp.deconnexion') }}" id="logout-button-sidebar" class="flex items-center p-3 text-red-500 hover:text-red-400 hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 161 |
+
<span class="material-symbols-rounded">logout</span>
|
| 162 |
+
<span class="ml-3">Déconnexion</span>
|
| 163 |
+
</a>
|
| 164 |
+
</nav>
|
| 165 |
+
|
| 166 |
+
<div class="absolute bottom-6 w-52 text-xs text-secondary-var transition-colors-theme">
|
| 167 |
+
<p>Connecté en tant que: <span class="font-semibold text-color-var transition-colors-theme">{{ user.email if user and user.email else 'Chargement...' }}</span></p>
|
| 168 |
+
<p>Plan: <span class="font-semibold text-color-var transition-colors-theme">{{ (user.plan | upper) if user and user.plan else 'GRATUIT' }}</span></p>
|
| 169 |
+
</div>
|
| 170 |
+
|
| 171 |
+
</aside>
|
| 172 |
+
|
| 173 |
+
<div id="main-content" class="main-content p-8 transition-colors-theme">
|
| 174 |
+
|
| 175 |
+
<header class="lg:hidden flex justify-between items-center mb-8">
|
| 176 |
+
<div class="flex items-center">
|
| 177 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 178 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Nexus Pro</span>
|
| 179 |
+
</div>
|
| 180 |
+
<button id="sidebar-toggle" class="p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme">
|
| 181 |
+
<span class="material-symbols-rounded text-color-var">menu</span>
|
| 182 |
+
</button>
|
| 183 |
+
</header>
|
| 184 |
+
|
| 185 |
+
<h1 class="text-3xl font-bold mb-8 text-color-var transition-colors-theme">Profil Utilisateur et Compte</h1>
|
| 186 |
+
|
| 187 |
+
{% with messages = get_flashed_messages(with_categories=true) %}
|
| 188 |
+
{% if messages %}
|
| 189 |
+
{% for category, message in messages %}
|
| 190 |
+
<div class="p-4 mb-4 text-sm rounded-lg border border-transparent
|
| 191 |
+
{{ 'bg-red-900/20 text-red-500 border-red-900' if category == 'error' or category == 'danger' or category == 'warning' else 'bg-green-900/20 text-green-500 border-green-900' }}" role="alert">
|
| 192 |
+
{{ message }}
|
| 193 |
+
</div>
|
| 194 |
+
{% endfor %}
|
| 195 |
+
{% endif %}
|
| 196 |
+
{% endwith %}
|
| 197 |
+
|
| 198 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme mb-8">
|
| 199 |
+
<h2 class="text-xl font-semibold mb-4 flex items-center text-color-var transition-colors-theme">
|
| 200 |
+
<span class="material-symbols-rounded mr-2">info</span>
|
| 201 |
+
Vos Informations de Compte
|
| 202 |
+
</h2>
|
| 203 |
+
<div class="space-y-3 text-secondary-var transition-colors-theme">
|
| 204 |
+
<p><strong>Nom d'utilisateur:</strong> <span class="text-color-var font-medium">{{ user.username if user and user.username else 'N/A' }}</span></p>
|
| 205 |
+
<p><strong>Adresse Email:</strong> <span class="text-color-var font-medium">{{ user.email if user and user.email else 'N/A' }}</span></p>
|
| 206 |
+
<p><strong>Plan d'abonnement:</strong> <span class="text-color-var font-medium">{{ (user.plan | upper) if user and user.plan else 'GRATUIT' }}</span></p>
|
| 207 |
+
<p><strong>Date d'inscription:</strong> <span class="text-color-var font-medium">{{ user.registration_date if user and user.registration_date else 'N/A' }}</span></p>
|
| 208 |
+
</div>
|
| 209 |
+
</div>
|
| 210 |
+
|
| 211 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme mb-8">
|
| 212 |
+
<h2 class="text-xl font-semibold mb-4 flex items-center text-color-var transition-colors-theme">
|
| 213 |
+
<span class="material-symbols-rounded mr-2 text-primary-color-var">edit</span>
|
| 214 |
+
Mettre à Jour le Profil et le Mot de Passe
|
| 215 |
+
</h2>
|
| 216 |
+
<p class="text-secondary-var mb-6 text-sm transition-colors-theme">Modifiez votre nom, votre adresse e-mail ou votre mot de passe. Remplissez uniquement les champs que vous souhaitez mettre à jour (sauf pour les champs Nom et Email).</p>
|
| 217 |
+
|
| 218 |
+
<form id="profile-update-form" method="POST" action="{{ url_for('user_bp.profile') }}">
|
| 219 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
| 220 |
+
<div class="mb-4">
|
| 221 |
+
<label for="username" class="block text-sm font-medium text-secondary-var mb-2 transition-colors-theme">Nom d'utilisateur</label>
|
| 222 |
+
<input type="text" id="username" name="username" value="{{ user.username if user and user.username else '' }}" required
|
| 223 |
+
class="w-full bg-input-var text-color-var p-3 rounded-lg border border-input-var focus:outline-none focus:ring-2 focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 224 |
+
</div>
|
| 225 |
+
|
| 226 |
+
<div class="mb-4">
|
| 227 |
+
<label for="email" class="block text-sm font-medium text-secondary-var mb-2 transition-colors-theme">Adresse E-mail</label>
|
| 228 |
+
<input type="email" id="email" name="email" value="{{ user.email if user and user.email else '' }}" required
|
| 229 |
+
class="w-full bg-input-var text-color-var p-3 rounded-lg border border-input-var focus:outline-none focus:ring-2 focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 230 |
+
</div>
|
| 231 |
+
</div>
|
| 232 |
+
|
| 233 |
+
<div class="border-t border-sidebar-var pt-6 mt-4">
|
| 234 |
+
<h3 class="text-lg font-semibold mb-4 flex items-center text-color-var transition-colors-theme">
|
| 235 |
+
<span class="material-symbols-rounded mr-2 text-primary-color-var">lock</span>
|
| 236 |
+
Changement de Mot de Passe (Optionnel)
|
| 237 |
+
</h3>
|
| 238 |
+
<p class="text-secondary-var mb-6 text-sm transition-colors-theme">Remplissez ces champs UNIQUEMENT si vous souhaitez changer votre mot de passe.</p>
|
| 239 |
+
|
| 240 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
| 241 |
+
<div class="mb-4">
|
| 242 |
+
<label for="new_password" class="block text-sm font-medium text-secondary-var mb-2 transition-colors-theme">Nouveau Mot de Passe</label>
|
| 243 |
+
<input type="password" id="new_password" name="new_password" placeholder="Laisser vide pour ne pas changer"
|
| 244 |
+
class="w-full bg-input-var text-color-var p-3 rounded-lg border border-input-var focus:outline-none focus:ring-2 focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 245 |
+
</div>
|
| 246 |
+
|
| 247 |
+
<div class="mb-4">
|
| 248 |
+
<label for="confirm_password" class="block text-sm font-medium text-secondary-var mb-2 transition-colors-theme">Confirmer le Nouveau Mot de Passe</label>
|
| 249 |
+
<input type="password" id="confirm_password" name="confirm_password" placeholder="Confirmer le nouveau mot de passe"
|
| 250 |
+
class="w-full bg-input-var text-color-var p-3 rounded-lg border border-input-var focus:outline-none focus:ring-2 focus:ring-primary-color-var focus:border-primary-color-var transition-colors-theme">
|
| 251 |
+
</div>
|
| 252 |
+
</div>
|
| 253 |
+
</div>
|
| 254 |
+
|
| 255 |
+
<div class="mt-6">
|
| 256 |
+
<button type="submit" class="w-full bg-primary-color-var hover:bg-primary-hover-var text-white font-bold py-3 px-4 transition duration-200 flex items-center justify-center btn-square transition-colors-theme">
|
| 257 |
+
<span class="material-symbols-rounded mr-2">save</span>
|
| 258 |
+
Sauvegarder les Changements
|
| 259 |
+
</button>
|
| 260 |
+
</div>
|
| 261 |
+
</form>
|
| 262 |
+
</div>
|
| 263 |
+
|
| 264 |
+
</div>
|
| 265 |
+
|
| 266 |
+
<script>
|
| 267 |
+
|
| 268 |
+
// Fonction utilitaire pour appliquer le thème
|
| 269 |
+
function applyTheme(theme) {
|
| 270 |
+
if (theme === 'dark') {
|
| 271 |
+
document.documentElement.classList.add('dark');
|
| 272 |
+
localStorage.setItem('theme', 'dark');
|
| 273 |
+
} else {
|
| 274 |
+
document.documentElement.classList.remove('dark');
|
| 275 |
+
localStorage.setItem('theme', 'light');
|
| 276 |
+
}
|
| 277 |
+
// Mettre à jour l'icône du switch si nécessaire
|
| 278 |
+
const icon = document.querySelector('#theme-switch .material-symbols-rounded');
|
| 279 |
+
if (icon) {
|
| 280 |
+
// S'assurer que l'icône reflète le mode ACTIF
|
| 281 |
+
icon.textContent = theme === 'dark' ? 'light_mode' : 'dark_mode';
|
| 282 |
+
}
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
// 1. Initialisation du thème au chargement
|
| 286 |
+
// Récupérer le thème sauvé ou utiliser 'dark' comme défaut
|
| 287 |
+
const savedTheme = localStorage.getItem('theme') || 'dark';
|
| 288 |
+
applyTheme(savedTheme);
|
| 289 |
+
|
| 290 |
+
// 2. Logique du switch de thème
|
| 291 |
+
document.getElementById('theme-switch').addEventListener('click', () => {
|
| 292 |
+
// Vérifier si la classe 'dark' est présente sur l'élément racine
|
| 293 |
+
const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
|
| 294 |
+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
| 295 |
+
applyTheme(newTheme);
|
| 296 |
+
});
|
| 297 |
+
|
| 298 |
+
// 3. Logique de bascule de la sidebar pour mobile/tablette
|
| 299 |
+
const sidebarToggle = document.getElementById('sidebar-toggle');
|
| 300 |
+
const sidebar = document.getElementById('sidebar');
|
| 301 |
+
|
| 302 |
+
if (sidebarToggle && sidebar) {
|
| 303 |
+
sidebarToggle.addEventListener('click', () => {
|
| 304 |
+
sidebar.classList.toggle('open');
|
| 305 |
+
});
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
// 4. Fermeture de la sidebar lors du clic sur un lien (pour mobile)
|
| 309 |
+
// Note: Assurez-vous que 'sidebar' est défini avant d'appeler querySelectorAll
|
| 310 |
+
if (sidebar) {
|
| 311 |
+
const sidebarLinks = sidebar.querySelectorAll('a');
|
| 312 |
+
if (sidebarLinks) {
|
| 313 |
+
sidebarLinks.forEach(link => {
|
| 314 |
+
link.addEventListener('click', () => {
|
| 315 |
+
// Fermer la sidebar uniquement sur les petits écrans
|
| 316 |
+
if (window.innerWidth < 1024) {
|
| 317 |
+
sidebar.classList.remove('open');
|
| 318 |
+
}
|
| 319 |
+
});
|
| 320 |
+
});
|
| 321 |
+
}
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
// 5. Logique de Déconnexion (Conservée)
|
| 325 |
+
const logoutHandler = async (e) => {
|
| 326 |
+
e.preventDefault();
|
| 327 |
+
// La déconnexion est gérée par la route Flask directe
|
| 328 |
+
window.location.href = document.getElementById('logout-button-sidebar').href;
|
| 329 |
+
};
|
| 330 |
+
// On attache l'événement à la déconnexion dans la sidebar.
|
| 331 |
+
const logoutButtonSidebar = document.getElementById('logout-button-sidebar');
|
| 332 |
+
if (logoutButtonSidebar) {
|
| 333 |
+
logoutButtonSidebar.addEventListener('click', logoutHandler);
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
</script>
|
| 337 |
+
</body>
|
| 338 |
+
</html>
|
templates/statut.html
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Nexus | Statut de l'API</title>
|
| 7 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<link rel="stylesheet"
|
| 10 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 11 |
+
<style>
|
| 12 |
+
/* Configuration de la police Inter */
|
| 13 |
+
body { font-family: 'Inter', sans-serif; }
|
| 14 |
+
|
| 15 |
+
/* Définition des variables de thème (Ajoutées pour le style) */
|
| 16 |
+
:root {
|
| 17 |
+
/* Couleurs de base (exemple - ajustez si nécessaire) */
|
| 18 |
+
--page-var: #f8fafc; /* light - slate-50 */
|
| 19 |
+
--color-var: #0f172a; /* light - slate-900 */
|
| 20 |
+
--secondary-var: #64748b; /* light - slate-500 */
|
| 21 |
+
--card-var: #ffffff; /* light - white */
|
| 22 |
+
--sidebar-var: #e2e8f0; /* light - slate-200 */
|
| 23 |
+
--sidebar-active-var: #cbd5e1; /* light - slate-300 */
|
| 24 |
+
--input-var: #f1f5f9; /* light - slate-100 */
|
| 25 |
+
--primary-color-var: #4f46e5; /* indigo-600 */
|
| 26 |
+
--primary-hover-var: #4338ca; /* indigo-700 */
|
| 27 |
+
--error-var: #fef2f2; /* red-50 */
|
| 28 |
+
--success-var: #f0fdf4; /* green-50 */
|
| 29 |
+
--warning-var: #fcd34d; /* amber-400 */
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
.dark {
|
| 33 |
+
--page-var: #18181b; /* dark - zinc-900 (Gris très foncé pour l'arrière-plan de la page) */
|
| 34 |
+
--color-var: #f4f4f5; /* dark - zinc-100 (Texte clair) */
|
| 35 |
+
--secondary-var: #a1a1aa; /* dark - zinc-400 (Texte secondaire) */
|
| 36 |
+
--card-var: #27272a; /* dark - zinc-800 (Gris foncé pour les cartes et la sidebar) */
|
| 37 |
+
--sidebar-var: #27272a; /* dark - zinc-800 */
|
| 38 |
+
--sidebar-active-var: #3f3f46; /* dark - zinc-700 (Gris un peu plus clair pour l'actif) */
|
| 39 |
+
--input-var: #18181b; /* dark - zinc-900 (Fond de champ de saisie) */
|
| 40 |
+
--primary-color-var: #6366f1; /* indigo-500 (Couleur primaire inchangée) */
|
| 41 |
+
--primary-hover-var: #4f46e5; /* indigo-600 */
|
| 42 |
+
--error-var: #450a0a; /* red-950 */
|
| 43 |
+
--success-var: #052e16; /* green-950 */
|
| 44 |
+
--warning-var: #b45309; /* amber-800 */
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
/* Transition pour un effet doux des couleurs */
|
| 48 |
+
.transition-colors-theme { transition: background-color 0.3s, color 0.3s, border-color 0.3s; }
|
| 49 |
+
|
| 50 |
+
/* Style et positionnement du bouton de Thème */
|
| 51 |
+
.theme-switch {
|
| 52 |
+
background: none;
|
| 53 |
+
border: none;
|
| 54 |
+
cursor: pointer;
|
| 55 |
+
font-size: 24px;
|
| 56 |
+
transition: color 0.2s;
|
| 57 |
+
position: fixed; /* Reste fixe même si le reste défile */
|
| 58 |
+
top: 1rem;
|
| 59 |
+
right: 1rem;
|
| 60 |
+
z-index: 50; /* Doit être au-dessus du reste */
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/* Style pour la sidebar responsive */
|
| 64 |
+
.sidebar {
|
| 65 |
+
position: fixed;
|
| 66 |
+
top: 0;
|
| 67 |
+
left: 0;
|
| 68 |
+
height: 100vh;
|
| 69 |
+
z-index: 40;
|
| 70 |
+
transform: translateX(-100%);
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
/* Styles pour le mode desktop/large screen */
|
| 74 |
+
@media (min-width: 1024px) {
|
| 75 |
+
.sidebar {
|
| 76 |
+
transform: translateX(0);
|
| 77 |
+
}
|
| 78 |
+
.main-content {
|
| 79 |
+
margin-left: 16rem; /* 64px width */
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
/* Styles pour le mode mobile/tablet */
|
| 84 |
+
@media (max-width: 1023px) {
|
| 85 |
+
.sidebar {
|
| 86 |
+
transition: transform 0.3s ease-in-out;
|
| 87 |
+
}
|
| 88 |
+
.sidebar.open {
|
| 89 |
+
transform: translateX(0);
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
/* Ajout des styles pour les variables CSS dans Tailwind */
|
| 94 |
+
.bg-page-var { background-color: var(--page-var); }
|
| 95 |
+
.text-color-var { color: var(--color-var); }
|
| 96 |
+
.text-secondary-var { color: var(--secondary-var); }
|
| 97 |
+
.bg-card-var { background-color: var(--card-var); }
|
| 98 |
+
.bg-sidebar-var { background-color: var(--sidebar-var); }
|
| 99 |
+
.border-sidebar-var { border-color: var(--sidebar-var); }
|
| 100 |
+
.bg-sidebar-active-var { background-color: var(--sidebar-active-var); }
|
| 101 |
+
.bg-input-var { background-color: var(--input-var); }
|
| 102 |
+
.border-input-var { border-color: var(--input-var); }
|
| 103 |
+
.text-primary-color-var { color: var(--primary-color-var); }
|
| 104 |
+
.focus\:ring-primary-color-var:focus { --tw-ring-color: var(--primary-color-var); }
|
| 105 |
+
.focus\:border-primary-color-var:focus { border-color: var(--primary-color-var); }
|
| 106 |
+
.bg-primary-color-var { background-color: var(--primary-color-var); }
|
| 107 |
+
.hover\:bg-primary-hover-var:hover { background-color: var(--primary-hover-var); }
|
| 108 |
+
.hover\:bg-sidebar-active-var:hover { background-color: var(--sidebar-active-var); }
|
| 109 |
+
.hover\:bg-sidebar-active-var\/80:hover { background-color: color-mix(in srgb, var(--sidebar-active-var) 80%, transparent); }
|
| 110 |
+
|
| 111 |
+
/* Correction pour les messages flash pour utiliser les variables */
|
| 112 |
+
.bg-red-900\/20 { background-color: color-mix(in srgb, var(--error-var) 20%, transparent); } /* Approximation des couleurs spécifiques */
|
| 113 |
+
.text-red-500 { color: #ef4444; } /* Laissez le rouge spécifique pour les erreurs */
|
| 114 |
+
.border-red-900 { border-color: #7f1d1d; } /* Laissez le rouge spécifique pour les erreurs */
|
| 115 |
+
.bg-green-900\/20 { background-color: color-mix(in srgb, var(--success-var) 20%, transparent); } /* Approximation des couleurs spécifiques */
|
| 116 |
+
.text-green-500 { color: #22c55e; } /* Laissez le vert spécifique pour le succès */
|
| 117 |
+
.border-green-900 { border-color: #064e3b; } /* Laissez le vert spécifique pour le succès */
|
| 118 |
+
.hover\:text-link-hover-var:hover { color: var(--secondary-var); } /* Ajout d'une pseudo-variable pour le hover de l'icône de thème (simple fallback) */
|
| 119 |
+
|
| 120 |
+
/* Nouveaux styles pour le statut de l'API */
|
| 121 |
+
.status-bar {
|
| 122 |
+
height: 1.5rem; /* 6px */
|
| 123 |
+
border-radius: 0.375rem; /* rounded-md */
|
| 124 |
+
transition: width 0.5s ease-out; /* Animation douce pour le changement de statut */
|
| 125 |
+
display: flex;
|
| 126 |
+
align-items: center;
|
| 127 |
+
padding-left: 0.75rem;
|
| 128 |
+
font-weight: 600;
|
| 129 |
+
color: white; /* Texte blanc par défaut pour la barre de statut */
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/* Couleurs spécifiques pour le statut */
|
| 133 |
+
.status-green { background-color: #22c55e; } /* green-500 */
|
| 134 |
+
.status-yellow { background-color: #f59e0b; } /* amber-500 */
|
| 135 |
+
.status-red { background-color: #ef4444; } /* red-500 */
|
| 136 |
+
|
| 137 |
+
</style>
|
| 138 |
+
</head>
|
| 139 |
+
|
| 140 |
+
<body class="bg-page-var text-color-var min-h-screen transition-colors-theme">
|
| 141 |
+
|
| 142 |
+
<button id="theme-switch" class="theme-switch text-color-var hover:text-link-hover-var transition-colors-theme">
|
| 143 |
+
<span class="material-symbols-rounded">dark_mode</span>
|
| 144 |
+
</button>
|
| 145 |
+
|
| 146 |
+
<aside id="sidebar" class="sidebar w-64 bg-sidebar-var border-r border-sidebar-var p-6 flex flex-col lg:block transition-colors-theme">
|
| 147 |
+
|
| 148 |
+
<div class="flex items-center mb-6 shrink-0">
|
| 149 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 150 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Nexus Pro</span>
|
| 151 |
+
</div>
|
| 152 |
+
|
| 153 |
+
<div class="flex-grow overflow-y-auto pr-2" id="scrollable-nav-container">
|
| 154 |
+
<nav class="space-y-3 pb-4">
|
| 155 |
+
<a href="{{ url_for('user_bp.dashboard') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 156 |
+
<span class="material-symbols-rounded">dashboard</span>
|
| 157 |
+
<span class="ml-3">Dashboard</span>
|
| 158 |
+
</a>
|
| 159 |
+
<a href="{{ url_for('user_bp.api_key') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 160 |
+
<span class="material-symbols-rounded">key</span>
|
| 161 |
+
<span class="ml-3">Clés API</span>
|
| 162 |
+
</a>
|
| 163 |
+
<a href="{{ url_for('user_bp.profile') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 164 |
+
<span class="material-symbols-rounded">person</span>
|
| 165 |
+
<span class="ml-3">Profil</span>
|
| 166 |
+
</a>
|
| 167 |
+
<a href="{{ url_for('user_bp.embed_forms') }}" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 168 |
+
<span class="material-symbols-rounded">code</span>
|
| 169 |
+
<span class="ml-3">Formulaires Embarqués</span>
|
| 170 |
+
</a>
|
| 171 |
+
<a href="/api_logs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 172 |
+
<span class="material-symbols-rounded">list_alt</span>
|
| 173 |
+
<span class="ml-3">Logs d'API</span>
|
| 174 |
+
</a>
|
| 175 |
+
<a href="/tarifs" class="flex items-center p-3 text-secondary-var hover:text-color-var hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 176 |
+
<span class="material-symbols-rounded">payments</span>
|
| 177 |
+
<span class="ml-3">Tarifs</span>
|
| 178 |
+
</a>
|
| 179 |
+
<a href="/statut" class="flex items-center p-3 bg-sidebar-active-var text-color-var rounded-lg transition duration-150 transition-colors-theme">
|
| 180 |
+
<span class="material-symbols-rounded">monitor_heart</span>
|
| 181 |
+
<span class="ml-3">Statut de l'API</span>
|
| 182 |
+
</a>
|
| 183 |
+
<a href="{{ url_for('user_bp.deconnexion') }}" id="logout-button-sidebar" class="flex items-center p-3 text-red-500 hover:text-red-400 hover:bg-sidebar-active-var rounded-lg transition duration-150 transition-colors-theme">
|
| 184 |
+
<span class="material-symbols-rounded">logout</span>
|
| 185 |
+
<span class="ml-3">Déconnexion</span>
|
| 186 |
+
</a>
|
| 187 |
+
</nav>
|
| 188 |
+
</div>
|
| 189 |
+
|
| 190 |
+
<div class="mt-auto pt-4 text-xs text-secondary-var transition-colors-theme border-t border-sidebar-var/50 shrink-0">
|
| 191 |
+
<p>Connecté en tant que: <span class="font-semibold text-color-var transition-colors-theme">{{ user.email if user and user.email else 'Chargement...' }}</span></p>
|
| 192 |
+
<p>Plan: <span class="font-semibold text-color-var transition-colors-theme">{{ (user.plan | upper) if user and user.plan else 'GRATUIT' }}</span></p>
|
| 193 |
+
</div>
|
| 194 |
+
|
| 195 |
+
</aside>
|
| 196 |
+
|
| 197 |
+
<div id="main-content" class="main-content p-8 transition-colors-theme">
|
| 198 |
+
|
| 199 |
+
<header class="lg:hidden flex justify-between items-center mb-8">
|
| 200 |
+
<div class="flex items-center">
|
| 201 |
+
<img src="https://i.imgur.com/7Gn3toV.png" alt="Nexus Pro Logo" class="h-8">
|
| 202 |
+
<span class="text-xl font-bold text-color-var ml-2 transition-colors-theme">Nexus Pro</span>
|
| 203 |
+
</div>
|
| 204 |
+
<button id="sidebar-toggle" class="p-2 rounded-lg bg-sidebar-active-var hover:bg-sidebar-active-var/80 transition-colors-theme">
|
| 205 |
+
<span class="material-symbols-rounded text-color-var">menu</span>
|
| 206 |
+
</button>
|
| 207 |
+
</header>
|
| 208 |
+
|
| 209 |
+
<h1 class="text-3xl font-bold mb-8 text-color-var transition-colors-theme">Statut de l'API Nexus</h1>
|
| 210 |
+
|
| 211 |
+
{% with messages = get_flashed_messages(with_categories=true) %}
|
| 212 |
+
{% if messages %}
|
| 213 |
+
{% for category, message in messages %}
|
| 214 |
+
<div class="p-4 mb-4 text-sm rounded-lg border border-transparent
|
| 215 |
+
{{ 'bg-red-900/20 text-red-500 border-red-900' if category == 'error' or category == 'danger' or category == 'warning' else 'bg-green-900/20 text-green-500 border-green-900' }}" role="alert">
|
| 216 |
+
{{ message }}
|
| 217 |
+
</div>
|
| 218 |
+
{% endfor %}
|
| 219 |
+
{% endif %}
|
| 220 |
+
{% endwith %}
|
| 221 |
+
|
| 222 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme mb-8">
|
| 223 |
+
<h2 class="text-xl font-semibold mb-4 flex items-center text-color-var transition-colors-theme">
|
| 224 |
+
<span class="material-symbols-rounded mr-2 text-primary-color-var">cloud_queue</span>
|
| 225 |
+
État Global du Service
|
| 226 |
+
</h2>
|
| 227 |
+
<div id="overall-status-display" class="p-4 rounded-lg text-lg font-bold text-white transition duration-300 shadow-md">
|
| 228 |
+
<p id="overall-status-text">Chargement du statut...</p>
|
| 229 |
+
</div>
|
| 230 |
+
</div>
|
| 231 |
+
|
| 232 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme mb-8">
|
| 233 |
+
<h2 class="text-xl font-semibold mb-6 flex items-center text-color-var transition-colors-theme">
|
| 234 |
+
<span class="material-symbols-rounded mr-2 text-primary-color-var">bar_chart</span>
|
| 235 |
+
Statut des Composants API
|
| 236 |
+
</h2>
|
| 237 |
+
|
| 238 |
+
<div class="space-y-6">
|
| 239 |
+
|
| 240 |
+
<div class="flex flex-col md:flex-row items-start md:items-center justify-between border-b border-sidebar-var pb-4">
|
| 241 |
+
<span class="text-lg font-medium text-color-var w-full md:w-1/3 mb-2 md:mb-0 transition-colors-theme">Service d'Authentification</span>
|
| 242 |
+
<div class="w-full md:w-2/3">
|
| 243 |
+
<div id="auth-status-bar" data-status="{{ api_status.auth }}" class="status-bar" style="width: 100%;" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
|
| 244 |
+
{{ api_status.auth_display if api_status and api_status.auth_display else 'Chargement...' }}
|
| 245 |
+
</div>
|
| 246 |
+
</div>
|
| 247 |
+
</div>
|
| 248 |
+
|
| 249 |
+
<div class="flex flex-col md:flex-row items-start md:items-center justify-between border-b border-sidebar-var pb-4">
|
| 250 |
+
<span class="text-lg font-medium text-color-var w-full md:w-1/3 mb-2 md:mb-0 transition-colors-theme">Traitement des Données (Endpoints V1)</span>
|
| 251 |
+
<div class="w-full md:w-2/3">
|
| 252 |
+
<div id="data-status-bar" data-status="{{ api_status.data_v1 }}" class="status-bar" style="width: 100%;" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
|
| 253 |
+
{{ api_status.data_v1_display if api_status and api_status.data_v1_display else 'Chargement...' }}
|
| 254 |
+
</div>
|
| 255 |
+
</div>
|
| 256 |
+
</div>
|
| 257 |
+
|
| 258 |
+
<div class="flex flex-col md:flex-row items-start md:items-center justify-between">
|
| 259 |
+
<span class="text-lg font-medium text-color-var w-full md:w-1/3 mb-2 md:mb-0 transition-colors-theme">Base de Données Principale</span>
|
| 260 |
+
<div class="w-full md:w-2/3">
|
| 261 |
+
<div id="db-status-bar" data-status="{{ api_status.database }}" class="status-bar" style="width: 100%;" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
|
| 262 |
+
{{ api_status.database_display if api_status and api_status.database_display else 'Chargement...' }}
|
| 263 |
+
</div>
|
| 264 |
+
</div>
|
| 265 |
+
</div>
|
| 266 |
+
|
| 267 |
+
</div>
|
| 268 |
+
|
| 269 |
+
<p class="mt-8 text-sm text-secondary-var">Dernière mise à jour: <span id="last-updated">{{ api_status.last_updated if api_status and api_status.last_updated else 'N/A' }}</span></p>
|
| 270 |
+
|
| 271 |
+
</div>
|
| 272 |
+
|
| 273 |
+
<div class="bg-card-var p-6 rounded-lg shadow-xl border border-sidebar-var transition-colors-theme">
|
| 274 |
+
<h2 class="text-xl font-semibold mb-4 flex items-center text-color-var transition-colors-theme">
|
| 275 |
+
<span class="material-symbols-rounded mr-2 text-primary-color-var">history</span>
|
| 276 |
+
Historique des Incidents
|
| 277 |
+
</h2>
|
| 278 |
+
|
| 279 |
+
{% if incidents %}
|
| 280 |
+
<ul class="space-y-4">
|
| 281 |
+
{% for incident in incidents %}
|
| 282 |
+
<li class="border-l-4 p-4 rounded-r-lg shadow-sm
|
| 283 |
+
{% if incident.status == 'resolved' %} border-green-500 bg-green-900/20 text-green-500
|
| 284 |
+
{% elif incident.status == 'monitoring' %} border-yellow-500 bg-yellow-900/20 text-yellow-500
|
| 285 |
+
{% elif incident.status == 'investigating' %} border-red-500 bg-red-900/20 text-red-500
|
| 286 |
+
{% else %} border-secondary-var bg-input-var text-secondary-var
|
| 287 |
+
{% endif %}">
|
| 288 |
+
<p class="font-bold">{{ incident.title }} -
|
| 289 |
+
<span class="text-sm font-normal uppercase">[{{ incident.status_display }}]</span></p>
|
| 290 |
+
<p class="text-sm mt-1">{{ incident.description }}</p>
|
| 291 |
+
<p class="text-xs mt-2 opacity-75">Date: {{ incident.date }}</p>
|
| 292 |
+
</li>
|
| 293 |
+
{% endfor %}
|
| 294 |
+
</ul>
|
| 295 |
+
{% else %}
|
| 296 |
+
<p class="text-secondary-var italic">Aucun incident récent à signaler. Le service est stable.</p>
|
| 297 |
+
{% endif %}
|
| 298 |
+
|
| 299 |
+
</div>
|
| 300 |
+
|
| 301 |
+
</div>
|
| 302 |
+
|
| 303 |
+
<script>
|
| 304 |
+
|
| 305 |
+
// Fonction utilitaire pour appliquer le thème
|
| 306 |
+
function applyTheme(theme) {
|
| 307 |
+
if (theme === 'dark') {
|
| 308 |
+
document.documentElement.classList.add('dark');
|
| 309 |
+
localStorage.setItem('theme', 'dark');
|
| 310 |
+
} else {
|
| 311 |
+
document.documentElement.classList.remove('dark');
|
| 312 |
+
localStorage.setItem('theme', 'light');
|
| 313 |
+
}
|
| 314 |
+
// Mettre à jour l'icône du switch si nécessaire
|
| 315 |
+
const icon = document.querySelector('#theme-switch .material-symbols-rounded');
|
| 316 |
+
if (icon) {
|
| 317 |
+
// S'assurer que l'icône reflète le mode ACTIF
|
| 318 |
+
icon.textContent = theme === 'dark' ? 'light_mode' : 'dark_mode';
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
// 1. Initialisation du thème au chargement
|
| 323 |
+
// Récupérer le thème sauvé ou utiliser 'dark' comme défaut
|
| 324 |
+
const savedTheme = localStorage.getItem('theme') || 'dark';
|
| 325 |
+
applyTheme(savedTheme);
|
| 326 |
+
|
| 327 |
+
// 2. Logique du switch de thème
|
| 328 |
+
document.getElementById('theme-switch').addEventListener('click', () => {
|
| 329 |
+
// Vérifier si la classe 'dark' est présente sur l'élément racine
|
| 330 |
+
const currentTheme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
|
| 331 |
+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
| 332 |
+
applyTheme(newTheme);
|
| 333 |
+
});
|
| 334 |
+
|
| 335 |
+
// 3. Logique de bascule de la sidebar pour mobile/tablette
|
| 336 |
+
const sidebarToggle = document.getElementById('sidebar-toggle');
|
| 337 |
+
const sidebar = document.getElementById('sidebar');
|
| 338 |
+
|
| 339 |
+
if (sidebarToggle && sidebar) {
|
| 340 |
+
sidebarToggle.addEventListener('click', () => {
|
| 341 |
+
sidebar.classList.toggle('open');
|
| 342 |
+
});
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
// 4. Fermeture de la sidebar lors du clic sur un lien (pour mobile)
|
| 346 |
+
if (sidebar) {
|
| 347 |
+
const sidebarLinks = sidebar.querySelectorAll('a');
|
| 348 |
+
if (sidebarLinks) {
|
| 349 |
+
sidebarLinks.forEach(link => {
|
| 350 |
+
link.addEventListener('click', () => {
|
| 351 |
+
// Fermer la sidebar uniquement sur les petits écrans
|
| 352 |
+
if (window.innerWidth < 1024) {
|
| 353 |
+
sidebar.classList.remove('open');
|
| 354 |
+
}
|
| 355 |
+
});
|
| 356 |
+
});
|
| 357 |
+
}
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
// 5. Logique de Déconnexion (Conservée)
|
| 361 |
+
const logoutHandler = async (e) => {
|
| 362 |
+
e.preventDefault();
|
| 363 |
+
// La déconnexion est gérée par la route Flask directe
|
| 364 |
+
window.location.href = document.getElementById('logout-button-sidebar').href;
|
| 365 |
+
};
|
| 366 |
+
// On attache l'événement à la déconnexion dans la sidebar.
|
| 367 |
+
const logoutButtonSidebar = document.getElementById('logout-button-sidebar');
|
| 368 |
+
if (logoutButtonSidebar) {
|
| 369 |
+
logoutButtonSidebar.addEventListener('click', logoutHandler);
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
// 6. Logique de Mise à Jour du Statut de l'API (Simulée pour l'exemple)
|
| 373 |
+
function updateStatusBar(elementId, status) {
|
| 374 |
+
const bar = document.getElementById(elementId);
|
| 375 |
+
if (!bar) return;
|
| 376 |
+
|
| 377 |
+
// Réinitialiser les classes de couleur
|
| 378 |
+
bar.classList.remove('status-green', 'status-yellow', 'status-red');
|
| 379 |
+
|
| 380 |
+
let colorClass = 'status-green';
|
| 381 |
+
let statusText = 'Opérationnel';
|
| 382 |
+
|
| 383 |
+
// Le statut peut venir de Jinja (comme 'operational', 'degraded', 'outage')
|
| 384 |
+
switch (status) {
|
| 385 |
+
case 'operational':
|
| 386 |
+
colorClass = 'status-green';
|
| 387 |
+
statusText = 'Opérationnel';
|
| 388 |
+
bar.style.width = '100%';
|
| 389 |
+
break;
|
| 390 |
+
case 'degraded':
|
| 391 |
+
colorClass = 'status-yellow';
|
| 392 |
+
statusText = 'Performance Dégradée';
|
| 393 |
+
bar.style.width = '80%'; // Visuel de barre partielle
|
| 394 |
+
break;
|
| 395 |
+
case 'outage':
|
| 396 |
+
colorClass = 'status-red';
|
| 397 |
+
statusText = 'Panne Majeure';
|
| 398 |
+
bar.style.width = '20%'; // Visuel de barre presque vide
|
| 399 |
+
break;
|
| 400 |
+
default:
|
| 401 |
+
colorClass = 'bg-secondary-var';
|
| 402 |
+
statusText = 'Indisponible / Inconnu';
|
| 403 |
+
bar.style.width = '100%';
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
bar.classList.add(colorClass);
|
| 407 |
+
// S'assurer que le texte est à jour (seulement si non fourni par Jinja)
|
| 408 |
+
if (bar.textContent.trim() === 'Chargement...') {
|
| 409 |
+
bar.textContent = statusText;
|
| 410 |
+
}
|
| 411 |
+
bar.setAttribute('aria-valuenow', bar.style.width.replace('%', ''));
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
function updateOverallStatus(authStatus, dataStatus, dbStatus) {
|
| 415 |
+
const display = document.getElementById('overall-status-display');
|
| 416 |
+
const text = document.getElementById('overall-status-text');
|
| 417 |
+
if (!display || !text) return;
|
| 418 |
+
|
| 419 |
+
display.classList.remove('bg-green-500', 'bg-yellow-500', 'bg-red-500', 'bg-secondary-var');
|
| 420 |
+
|
| 421 |
+
// Logique de statut général
|
| 422 |
+
if (authStatus === 'outage' || dataStatus === 'outage' || dbStatus === 'outage') {
|
| 423 |
+
display.classList.add('bg-red-500');
|
| 424 |
+
text.textContent = 'PANNE MAJEURE - Nous enquêtons sur un problème.';
|
| 425 |
+
} else if (authStatus === 'degraded' || dataStatus === 'degraded' || dbStatus === 'degraded') {
|
| 426 |
+
display.classList.add('bg-yellow-500');
|
| 427 |
+
text.textContent = 'PERFORMANCE DÉGRADÉE - Certains services sont affectés.';
|
| 428 |
+
} else if (authStatus === 'operational' && dataStatus === 'operational' && dbStatus === 'operational') {
|
| 429 |
+
display.classList.add('bg-green-500');
|
| 430 |
+
text.textContent = 'TOUT EST OPÉRATIONNEL - L\'API fonctionne normalement.';
|
| 431 |
+
} else {
|
| 432 |
+
display.classList.add('bg-secondary-var');
|
| 433 |
+
text.textContent = 'Statut Indéterminé.';
|
| 434 |
+
}
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
// Fonction pour lire les statuts depuis les attributs de données (simulant le backend)
|
| 438 |
+
function initializeStatus() {
|
| 439 |
+
// Lecture des données Jinja2 pré-remplies (simulées)
|
| 440 |
+
const authStatus = document.getElementById('auth-status-bar').dataset.status || 'operational';
|
| 441 |
+
const dataStatus = document.getElementById('data-status-bar').dataset.status || 'operational';
|
| 442 |
+
const dbStatus = document.getElementById('db-status-bar').dataset.status || 'operational';
|
| 443 |
+
|
| 444 |
+
// Mise à jour visuelle
|
| 445 |
+
updateStatusBar('auth-status-bar', authStatus);
|
| 446 |
+
updateStatusBar('data-status-bar', dataStatus);
|
| 447 |
+
updateStatusBar('db-status-bar', dbStatus);
|
| 448 |
+
updateOverallStatus(authStatus, dataStatus, dbStatus);
|
| 449 |
+
|
| 450 |
+
// ** Simulation d'une mise à jour en temps réel (Animation) **
|
| 451 |
+
// Dans une application réelle, cette fonction appellerait une API / WebSocket.
|
| 452 |
+
// Pour l'exemple, nous allons animer les barres après le chargement initial.
|
| 453 |
+
|
| 454 |
+
setTimeout(() => {
|
| 455 |
+
// Le backend peut ajuster la largeur pour montrer la "santé" (par exemple, 90% pour opé)
|
| 456 |
+
// Ici, nous utilisons juste les couleurs/texte basés sur le statut simple (operational/degraded/outage)
|
| 457 |
+
document.getElementById('auth-status-bar').style.width = authStatus === 'operational' ? '100%' : (authStatus === 'degraded' ? '80%' : '20%');
|
| 458 |
+
document.getElementById('data-status-bar').style.width = dataStatus === 'operational' ? '100%' : (dataStatus === 'degraded' ? '80%' : '20%');
|
| 459 |
+
document.getElementById('db-status-bar').style.width = dbStatus === 'operational' ? '100%' : (dbStatus === 'degraded' ? '80%' : '20%');
|
| 460 |
+
}, 100); // Petite pause pour l'effet de chargement initial.
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
// 7. Initialisation du statut au chargement de la page
|
| 464 |
+
document.addEventListener('DOMContentLoaded', initializeStatus);
|
| 465 |
+
|
| 466 |
+
</script>
|
| 467 |
+
</body>
|
| 468 |
+
</html>
|
templates/support.html
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Support & Contact - Nexus</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet"
|
| 9 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 10 |
+
<style>
|
| 11 |
+
body { font-family: 'Inter', sans-serif; }
|
| 12 |
+
|
| 13 |
+
/* Étape 2 : Définir les Variables de Thème (SOMBRE par défaut) */
|
| 14 |
+
:root {
|
| 15 |
+
/* Couleurs SOMBRE (Noir très foncé pour le fond) */
|
| 16 |
+
--bg-darker: #0A0A0A; /* Très foncé pour la barre ou le footer */
|
| 17 |
+
--bg-default: #121212; /* Fond général */
|
| 18 |
+
--bg-form: #1F1F1F; /* Fond des blocs de contenu */
|
| 19 |
+
--text-color: #E3E3E3;
|
| 20 |
+
--input-bg: #2C2C2C;
|
| 21 |
+
--input-border: #2C2C2C;
|
| 22 |
+
--header-border: #333333; /* Bordure plus discrète */
|
| 23 |
+
--blue-500: #3B82F6; /* Couleur primaire pour rester visible */
|
| 24 |
+
--blue-600: #2563EB;
|
| 25 |
+
--blue-700: #1D4ED8;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/* Mode CLAIR */
|
| 29 |
+
html.light {
|
| 30 |
+
/* Couleurs CLAIR */
|
| 31 |
+
--bg-darker: #FFFFFF;
|
| 32 |
+
--bg-default: #F7F7F7;
|
| 33 |
+
--bg-form: #FFFFFF;
|
| 34 |
+
--text-color: #333333;
|
| 35 |
+
--input-bg: #EAEAEA;
|
| 36 |
+
--input-border: #D1D5DB;
|
| 37 |
+
--header-border: #E5E7EB;
|
| 38 |
+
--blue-500: #1D4ED8;
|
| 39 |
+
--blue-600: #2563EB;
|
| 40 |
+
--blue-700: #1D4ED8;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
/* Appliquer les variables et transitions */
|
| 44 |
+
body {
|
| 45 |
+
background-color: var(--bg-default) !important;
|
| 46 |
+
color: var(--text-color) !important;
|
| 47 |
+
transition: background-color 0.3s, color 0.3s;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
/* Réinitialiser les classes Tailwind par défaut pour utiliser les variables */
|
| 51 |
+
.bg-gray-900 { background-color: var(--bg-default) !important; }
|
| 52 |
+
.bg-gray-800 { background-color: var(--bg-form) !important; }
|
| 53 |
+
.bg-gray-700 { background-color: var(--input-bg) !important; }
|
| 54 |
+
.text-white { color: var(--text-color) !important; }
|
| 55 |
+
.text-gray-300 { color: var(--text-color) !important; }
|
| 56 |
+
.text-gray-400 { color: #A0A0A0 !important; } /* Garder gris pour les textes secondaires */
|
| 57 |
+
.text-gray-500 { color: #888888 !important; }
|
| 58 |
+
|
| 59 |
+
.border-gray-700 { border-color: var(--header-border) !important; }
|
| 60 |
+
.border-blue-500\/50 { border-color: color-mix(in srgb, var(--blue-500) 50%, transparent) !important; }
|
| 61 |
+
.text-blue-500 { color: var(--blue-500) !important; }
|
| 62 |
+
|
| 63 |
+
.bg-blue-600 { background-color: var(--blue-600) !important; }
|
| 64 |
+
.hover\:bg-blue-700:hover { background-color: var(--blue-700) !important; }
|
| 65 |
+
.hover\:text-blue-500:hover { color: var(--blue-500) !important; }
|
| 66 |
+
.border-blue-600 { border-color: var(--blue-600) !important; }
|
| 67 |
+
|
| 68 |
+
/* Style du bouton de thème */
|
| 69 |
+
#theme-toggle {
|
| 70 |
+
background: none;
|
| 71 |
+
border: none;
|
| 72 |
+
cursor: pointer;
|
| 73 |
+
color: var(--text-color);
|
| 74 |
+
font-size: 24px;
|
| 75 |
+
transition: color 0.2s;
|
| 76 |
+
margin-right: 16px; /* Espace à droite du bouton */
|
| 77 |
+
}
|
| 78 |
+
</style>
|
| 79 |
+
</head>
|
| 80 |
+
<body class="bg-gray-900 text-white min-h-screen">
|
| 81 |
+
|
| 82 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8">
|
| 83 |
+
|
| 84 |
+
<header class="flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8
|
| 85 |
+
bg-[var(--bg-default)] sticky top-0 z-50 transition duration-300 shadow-xl shadow-black/20">
|
| 86 |
+
<h1 class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 87 |
+
Support & Contact
|
| 88 |
+
</h1>
|
| 89 |
+
<nav class="flex items-center space-x-4">
|
| 90 |
+
<button id="theme-toggle" aria-label="Basculer le thème">
|
| 91 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 92 |
+
</button>
|
| 93 |
+
<a href="/" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 94 |
+
Accueil
|
| 95 |
+
</a>
|
| 96 |
+
{% if is_logged_in %}
|
| 97 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg transition duration-200 font-medium">
|
| 98 |
+
Dashboard
|
| 99 |
+
</a>
|
| 100 |
+
{% else %}
|
| 101 |
+
<a href="/connexion" class="px-4 py-2 border-2 border-blue-600 text-blue-600 rounded-lg hover:bg-blue-600 hover:text-white font-medium transition duration-200">
|
| 102 |
+
Connexion
|
| 103 |
+
</a>
|
| 104 |
+
{% endif %}
|
| 105 |
+
</nav>
|
| 106 |
+
</header>
|
| 107 |
+
|
| 108 |
+
<main class="space-y-10 max-w-2xl mx-auto">
|
| 109 |
+
|
| 110 |
+
<div class="p-8 bg-gray-800 rounded-xl shadow-2xl border-l-4 border-blue-500">
|
| 111 |
+
|
| 112 |
+
{% if is_logged_in %}
|
| 113 |
+
<h2 class="text-3xl font-bold text-blue-500 mb-4">Envoyer une Requête (Connecté)</h2>
|
| 114 |
+
<p class="text-gray-300 mb-6">
|
| 115 |
+
Votre ID utilisateur ({{ user_id }}) sera automatiquement attaché à votre ticket, garantissant un traitement plus rapide.
|
| 116 |
+
</p>
|
| 117 |
+
{% else %}
|
| 118 |
+
<h2 class="text-3xl font-bold text-blue-500 mb-4">Contactez notre Équipe</h2>
|
| 119 |
+
<p class="text-gray-300 mb-6">
|
| 120 |
+
Veuillez vous connecter pour un support prioritaire.
|
| 121 |
+
</p>
|
| 122 |
+
{% endif %}
|
| 123 |
+
|
| 124 |
+
<form id="supportForm" class="space-y-6">
|
| 125 |
+
<div>
|
| 126 |
+
<label for="subject" class="block text-sm font-medium text-gray-300 mb-1">Sujet de la Requête</label>
|
| 127 |
+
<input type="text" id="subject" name="subject" required
|
| 128 |
+
class="w-full px-4 py-3 bg-gray-700 text-white border-2 border-gray-700 rounded-lg focus:border-blue-500 transition duration-200"
|
| 129 |
+
placeholder="Problème de connexion, Question de facturation...">
|
| 130 |
+
</div>
|
| 131 |
+
|
| 132 |
+
<div>
|
| 133 |
+
<label for="email" class="block text-sm font-medium text-gray-300 mb-1">Votre E-mail</label>
|
| 134 |
+
<input type="email" id="email" name="email" required
|
| 135 |
+
class="w-full px-4 py-3 bg-gray-700 text-white border-2 border-gray-700 rounded-lg focus:border-blue-500 transition duration-200"
|
| 136 |
+
placeholder="votre.email@exemple.com"
|
| 137 |
+
value="{% if is_logged_in %}L'email serait ici (via API){% endif %}">
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<div>
|
| 141 |
+
<label for="message" class="block text-sm font-medium text-gray-300 mb-1">Message</label>
|
| 142 |
+
<textarea id="message" name="message" rows="5" required
|
| 143 |
+
class="w-full px-4 py-3 bg-gray-700 text-white border-2 border-gray-700 rounded-lg focus:border-blue-500 transition duration-200"
|
| 144 |
+
placeholder="Décrivez votre problème ou votre question en détail."></textarea>
|
| 145 |
+
</div>
|
| 146 |
+
|
| 147 |
+
<div id="messageBoxSupport" class="text-sm p-3 rounded-lg hidden" role="alert"></div>
|
| 148 |
+
|
| 149 |
+
<button type="submit"
|
| 150 |
+
class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-lg transition duration-300 shadow-lg">
|
| 151 |
+
Envoyer le Message
|
| 152 |
+
</button>
|
| 153 |
+
</form>
|
| 154 |
+
</div>
|
| 155 |
+
</main>
|
| 156 |
+
|
| 157 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 158 |
+
© 2024 Nexus. Tous droits réservés.
|
| 159 |
+
</footer>
|
| 160 |
+
</div>
|
| 161 |
+
|
| 162 |
+
<script>
|
| 163 |
+
// Logique de bascule du mode sombre/clair (Étape 3)
|
| 164 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 165 |
+
const htmlElement = document.documentElement;
|
| 166 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 167 |
+
|
| 168 |
+
// Charger le thème depuis le localStorage
|
| 169 |
+
const savedTheme = localStorage.getItem('theme');
|
| 170 |
+
if (savedTheme === 'light') {
|
| 171 |
+
htmlElement.classList.add('light');
|
| 172 |
+
iconElement.textContent = 'dark_mode'; // Afficher l'icône "Sombre" en mode clair
|
| 173 |
+
} else {
|
| 174 |
+
// Default is 'dark' (or first visit)
|
| 175 |
+
iconElement.textContent = 'light_mode'; // Afficher l'icône "Clair" en mode sombre
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
themeToggle.addEventListener('click', () => {
|
| 179 |
+
if (htmlElement.classList.contains('light')) {
|
| 180 |
+
// Passage du mode Clair au mode Sombre
|
| 181 |
+
htmlElement.classList.remove('light');
|
| 182 |
+
localStorage.setItem('theme', 'dark');
|
| 183 |
+
iconElement.textContent = 'light_mode';
|
| 184 |
+
} else {
|
| 185 |
+
// Passage du mode Sombre au mode Clair
|
| 186 |
+
htmlElement.classList.add('light');
|
| 187 |
+
localStorage.setItem('theme', 'light');
|
| 188 |
+
iconElement.textContent = 'dark_mode';
|
| 189 |
+
}
|
| 190 |
+
});
|
| 191 |
+
|
| 192 |
+
// Logique du formulaire de support (existante)
|
| 193 |
+
document.getElementById('supportForm').addEventListener('submit', async (event) => {
|
| 194 |
+
event.preventDefault();
|
| 195 |
+
|
| 196 |
+
const subject = document.getElementById('subject').value;
|
| 197 |
+
const email = document.getElementById('email').value;
|
| 198 |
+
const message = document.getElementById('message').value;
|
| 199 |
+
const messageBox = document.getElementById('messageBoxSupport');
|
| 200 |
+
messageBox.classList.add('hidden');
|
| 201 |
+
messageBox.textContent = '';
|
| 202 |
+
|
| 203 |
+
const formData = {
|
| 204 |
+
subject,
|
| 205 |
+
email,
|
| 206 |
+
message,
|
| 207 |
+
{% if is_logged_in %}
|
| 208 |
+
user_id: "{{ user_id }}" // Ajout automatique de l'ID si connecté
|
| 209 |
+
{% else %}
|
| 210 |
+
user_id: null
|
| 211 |
+
{% endif %}
|
| 212 |
+
};
|
| 213 |
+
|
| 214 |
+
try {
|
| 215 |
+
// Utiliser la route proxy Flask pour contacter l'API Nexus
|
| 216 |
+
const response = await fetch('/api/support', {
|
| 217 |
+
method: 'POST',
|
| 218 |
+
headers: { 'Content-Type': 'application/json' },
|
| 219 |
+
body: JSON.stringify(formData)
|
| 220 |
+
});
|
| 221 |
+
|
| 222 |
+
// Simuler la réponse, car la route /api/support est un placeholder dans app.py
|
| 223 |
+
const data = await response.json();
|
| 224 |
+
|
| 225 |
+
// Si la route /api/support n'est qu'un proxy sans réponse complète, on simule:
|
| 226 |
+
if (response.ok) {
|
| 227 |
+
messageBox.classList.remove('bg-red-900/50', 'text-red-300');
|
| 228 |
+
messageBox.classList.add('bg-green-900/50', 'text-green-300');
|
| 229 |
+
messageBox.textContent = "Votre requête a été envoyée avec succès ! (Simulé pour l'API Nexus)";
|
| 230 |
+
document.getElementById('supportForm').reset();
|
| 231 |
+
} else {
|
| 232 |
+
messageBox.classList.remove('bg-green-900/50', 'text-green-300');
|
| 233 |
+
messageBox.classList.add('bg-red-900/50', 'text-red-300');
|
| 234 |
+
messageBox.textContent = data.message || "Erreur lors de l'envoi. Veuillez réessayer.";
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
messageBox.classList.remove('hidden');
|
| 238 |
+
|
| 239 |
+
} catch (error) {
|
| 240 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 241 |
+
messageBox.classList.remove('bg-green-900/50', 'text-green-300');
|
| 242 |
+
messageBox.classList.add('bg-red-900/50', 'text-red-300');
|
| 243 |
+
messageBox.textContent = "Impossible de contacter le serveur. Veuillez réessayer.";
|
| 244 |
+
messageBox.classList.remove('hidden');
|
| 245 |
+
}
|
| 246 |
+
});
|
| 247 |
+
</script>
|
| 248 |
+
|
| 249 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900">
|
| 250 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 251 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 252 |
+
|
| 253 |
+
<div class="col-span-2 lg:col-span-1">
|
| 254 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 255 |
+
<p class="mt-3 text-gray-400">
|
| 256 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 257 |
+
</p>
|
| 258 |
+
<div class="mt-4 flex space-x-4">
|
| 259 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 260 |
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.014 4.85.07c3.275.146 4.47 1.583 4.61 4.85.056 1.266.07 1.646.07 4.85s-.014 3.584-.07 4.85c-.14 3.267-1.335 4.704-4.61 4.85-1.266.056-1.646.07-4.85.07s-3.584-.014-4.85-.07c-3.275-.146-4.47-1.583-4.61-4.85-.056-1.266-.07-1.646-.07-4.85s.014-3.584.07-4.85c.14-3.267 1.335-4.704 4.61-4.85 1.266-.056 1.646-.07 4.85-.07zM12 0c-3.784 0-4.285.016-5.773.083-4.722.211-6.755 2.24-6.965 6.965C.016 7.715 0 8.216 0 12s.016 4.285.083 5.773c.21 4.721 2.239 6.755 6.965 6.965 1.488.067 1.99.083 5.773.083s4.285-.016 5.773-.083c4.721-.21 6.755-2.239 6.965-6.965.067-1.488.083-1.99.083-5.773s-.016-4.285-.083-5.773c-.21-4.722-2.239-6.755-6.965-6.965C16.285.016 15.784 0 12 0zm0 14.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z"/></svg>
|
| 261 |
+
</a>
|
| 262 |
+
</div>
|
| 263 |
+
</div>
|
| 264 |
+
|
| 265 |
+
<div>
|
| 266 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 267 |
+
<ul class="space-y-3 text-gray-400">
|
| 268 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 269 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 270 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 271 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 272 |
+
</ul>
|
| 273 |
+
</div>
|
| 274 |
+
|
| 275 |
+
<div>
|
| 276 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 277 |
+
<ul class="space-y-3 text-gray-400">
|
| 278 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 279 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 280 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 281 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 282 |
+
</ul>
|
| 283 |
+
</div>
|
| 284 |
+
|
| 285 |
+
<div class="col-span-2 md:col-span-1">
|
| 286 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 287 |
+
<ul class="space-y-3 text-gray-400">
|
| 288 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 289 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 290 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 291 |
+
</ul>
|
| 292 |
+
</div>
|
| 293 |
+
|
| 294 |
+
</div>
|
| 295 |
+
|
| 296 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm">
|
| 297 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 298 |
+
</div>
|
| 299 |
+
</div>
|
| 300 |
+
</footer>
|
| 301 |
+
|
| 302 |
+
</body>
|
| 303 |
+
</html>
|
templates/tarifs.html
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fr" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<link rel="icon" type="image/png" href="https://i.imgur.com/7Gn3toV.png">
|
| 7 |
+
<title>Tarifs - Nexus Pro</title>
|
| 8 |
+
<link rel="stylesheet"
|
| 9 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 10 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 11 |
+
<style>
|
| 12 |
+
/* Assure une meilleure compatibilité responsive pour la grille */
|
| 13 |
+
.pricing-grid {
|
| 14 |
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Variables de Thème - Couleurs Noir Foncé (Mode Sombre par défaut) */
|
| 18 |
+
:root, html.dark {
|
| 19 |
+
--bg-page: #181818; /* Noir très foncé, pas de bleu marine */
|
| 20 |
+
--bg-card: #282828;
|
| 21 |
+
--text-main: #EAEAEA;
|
| 22 |
+
--text-secondary: #B0B0B0;
|
| 23 |
+
--border-color: #404040;
|
| 24 |
+
--shadow-color: rgba(0, 0, 0, 0.5);
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/* Mode Clair */
|
| 28 |
+
html.light {
|
| 29 |
+
--bg-page: #F5F5F5;
|
| 30 |
+
--bg-card: #FFFFFF;
|
| 31 |
+
--text-main: #202020;
|
| 32 |
+
--text-secondary: #5C5C5C;
|
| 33 |
+
--border-color: #E0E0E0;
|
| 34 |
+
--shadow-color: rgba(0, 0, 0, 0.1);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
/* Application des variables */
|
| 38 |
+
body {
|
| 39 |
+
background-color: var(--bg-page);
|
| 40 |
+
color: var(--text-main);
|
| 41 |
+
transition: background-color 0.3s, color 0.3s;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
.bg-gray-900 { background-color: var(--bg-page) !important; }
|
| 45 |
+
.text-white { color: var(--text-main) !important; }
|
| 46 |
+
.bg-gray-800, .bg-gray-800\/50 {
|
| 47 |
+
background-color: var(--bg-card) !important;
|
| 48 |
+
box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -2px var(--shadow-color);
|
| 49 |
+
}
|
| 50 |
+
.text-gray-400 { color: var(--text-secondary) !important; }
|
| 51 |
+
.border-gray-700, .border-gray-800 { border-color: var(--border-color) !important; }
|
| 52 |
+
.text-gray-300 { color: var(--text-secondary) !important; } /* Utilisation de la même couleur pour uniformité */
|
| 53 |
+
.bg-gray-700 { background-color: #404040 !important; }
|
| 54 |
+
.theme-switch {
|
| 55 |
+
background: none;
|
| 56 |
+
border: none;
|
| 57 |
+
cursor: pointer;
|
| 58 |
+
color: var(--text-main);
|
| 59 |
+
font-size: 24px;
|
| 60 |
+
transition: color 0.2s;
|
| 61 |
+
padding: 0.5rem; /* Espace autour du bouton */
|
| 62 |
+
}
|
| 63 |
+
</style>
|
| 64 |
+
</head>
|
| 65 |
+
<body class="min-h-screen">
|
| 66 |
+
|
| 67 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 68 |
+
|
| 69 |
+
<header class="sticky top-0 z-50 flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8 bg-gray-900" style="background-color: var(--bg-page); transition: background-color 0.3s;">
|
| 70 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 71 |
+
NEXUS
|
| 72 |
+
</a>
|
| 73 |
+
<nav class="flex items-center space-x-4">
|
| 74 |
+
<a href="/documentation" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 75 |
+
Documentation
|
| 76 |
+
</a>
|
| 77 |
+
<a href="/a-propos" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 78 |
+
À Propos
|
| 79 |
+
</a>
|
| 80 |
+
|
| 81 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 82 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 83 |
+
</button>
|
| 84 |
+
|
| 85 |
+
{% if is_logged_in %}
|
| 86 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 border border-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 87 |
+
Dashboard
|
| 88 |
+
</a>
|
| 89 |
+
{% else %}
|
| 90 |
+
<a href="/connexion" class="px-4 py-2 bg-blue-600 border border-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 91 |
+
Connexion
|
| 92 |
+
</a>
|
| 93 |
+
{% endif %}
|
| 94 |
+
</nav>
|
| 95 |
+
</header>
|
| 96 |
+
|
| 97 |
+
<main class="space-y-12">
|
| 98 |
+
|
| 99 |
+
<section class="text-center p-8 bg-gray-800/50 shadow-lg">
|
| 100 |
+
<h1 class="text-5xl font-extrabold text-white mb-4 leading-tight">
|
| 101 |
+
Plans de Tarification
|
| 102 |
+
</h1>
|
| 103 |
+
<p class="text-xl text-gray-300 max-w-3xl mx-auto">
|
| 104 |
+
Sécurité robuste et évolutive. Choisissez le plan adapté à votre nombre d'utilisateurs.
|
| 105 |
+
</p>
|
| 106 |
+
|
| 107 |
+
<div class="mt-8 flex justify-center">
|
| 108 |
+
<div class="inline-flex bg-gray-700 p-1 rounded-full shadow-inner">
|
| 109 |
+
<button id="monthly-btn" class="px-6 py-2 text-sm font-semibold bg-blue-600 text-white shadow-md transition duration-200 rounded-full">
|
| 110 |
+
Mensuel
|
| 111 |
+
</button>
|
| 112 |
+
<button id="annual-btn" class="px-6 py-2 text-sm font-semibold text-gray-300 hover:text-white transition duration-200 rounded-full relative">
|
| 113 |
+
Annuel
|
| 114 |
+
<span class="ml-2 px-2 py-0.5 bg-yellow-500 text-black text-xs font-bold rounded-full">
|
| 115 |
+
ÉCONOMISEZ ~17%
|
| 116 |
+
</span>
|
| 117 |
+
</button>
|
| 118 |
+
</div>
|
| 119 |
+
</div>
|
| 120 |
+
|
| 121 |
+
</section>
|
| 122 |
+
|
| 123 |
+
<div class="grid pricing-grid gap-8">
|
| 124 |
+
|
| 125 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-teal-300 flex flex-col">
|
| 126 |
+
<h2 class="text-2xl font-bold text-teal-400 mb-2">Développeur</h2>
|
| 127 |
+
<p class="text-gray-400 mb-6 text-sm">Tests et prototypes.</p>
|
| 128 |
+
|
| 129 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 130 |
+
0<span class="text-xl text-gray-400 price-unit"> €/mois</span>
|
| 131 |
+
</div>
|
| 132 |
+
|
| 133 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 134 |
+
Jusqu'à 500 Comptes Utilisateurs
|
| 135 |
+
</div>
|
| 136 |
+
|
| 137 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 138 |
+
<li class="flex items-start text-gray-300">
|
| 139 |
+
<svg class="w-5 h-5 text-teal-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 140 |
+
Authentification Sécurisée (API & URL)
|
| 141 |
+
</li>
|
| 142 |
+
<li class="flex items-start text-gray-300">
|
| 143 |
+
<svg class="w-5 h-5 text-teal-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 144 |
+
Logs d'activité de base
|
| 145 |
+
</li>
|
| 146 |
+
<li class="flex items-start text-gray-300">
|
| 147 |
+
<svg class="w-5 h-5 text-teal-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 148 |
+
Support par email communautaire
|
| 149 |
+
</li>
|
| 150 |
+
</ul>
|
| 151 |
+
|
| 152 |
+
<a href="/inscription" class="mt-8 block text-center px-6 py-3 bg-teal-600 text-white text-lg font-bold shadow-md hover:bg-teal-700 transition duration-300 plan-button" data-plan="developer">
|
| 153 |
+
Commencer Gratuitement
|
| 154 |
+
</a>
|
| 155 |
+
</div>
|
| 156 |
+
|
| 157 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-yellow-500 flex flex-col">
|
| 158 |
+
<h2 class="text-2xl font-bold text-yellow-400 mb-2">Standard</h2>
|
| 159 |
+
<p class="text-gray-400 mb-6 text-sm">Premier pas vers la production.</p>
|
| 160 |
+
|
| 161 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 162 |
+
<span class="monthly-price" data-price="5">5</span>
|
| 163 |
+
<span class="annual-price hidden" data-price="50">50</span>
|
| 164 |
+
<span class="text-xl text-gray-400 price-unit"> €/mois</span>
|
| 165 |
+
</div>
|
| 166 |
+
|
| 167 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 168 |
+
Jusqu'à 1 000 Comptes Utilisateurs
|
| 169 |
+
</div>
|
| 170 |
+
|
| 171 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 172 |
+
<li class="flex items-start text-gray-300">
|
| 173 |
+
<svg class="w-5 h-5 text-yellow-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 174 |
+
Authentification Sécurisée
|
| 175 |
+
</li>
|
| 176 |
+
<li class="flex items-start text-gray-300">
|
| 177 |
+
<svg class="w-5 h-5 text-yellow-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 178 |
+
Logs d'activité avancés
|
| 179 |
+
</li>
|
| 180 |
+
<li class="flex items-start text-gray-300">
|
| 181 |
+
<svg class="w-5 h-5 text-yellow-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 182 |
+
Support par email standard (24-48h)
|
| 183 |
+
</li>
|
| 184 |
+
<li class="flex items-start text-gray-300">
|
| 185 |
+
<svg class="w-5 h-5 text-yellow-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 186 |
+
Option de dépassement ($/100 comptes)
|
| 187 |
+
</li>
|
| 188 |
+
</ul>
|
| 189 |
+
|
| 190 |
+
<a href="/checkout?plan=standard_monthly" class="mt-8 block text-center px-6 py-3 bg-yellow-600 text-white text-lg font-bold shadow-md hover:bg-yellow-700 transition duration-300 plan-button" data-plan="standard">
|
| 191 |
+
Choisir Standard
|
| 192 |
+
</a>
|
| 193 |
+
</div>
|
| 194 |
+
|
| 195 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-blue-500 flex flex-col relative">
|
| 196 |
+
<span class="absolute top-0 right-0 -mt-3 -mr-3 bg-indigo-500 text-white font-bold py-1 px-3 shadow-lg text-xs">POPULAIRE</span>
|
| 197 |
+
<h2 class="text-2xl font-bold text-blue-400 mb-2">Professionnel</h2>
|
| 198 |
+
<p class="text-gray-400 mb-6 text-sm">Croissance et haute disponibilité.</p>
|
| 199 |
+
|
| 200 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 201 |
+
<span class="monthly-price" data-price="10">10</span>
|
| 202 |
+
<span class="annual-price hidden" data-price="100">100</span>
|
| 203 |
+
<span class="text-xl text-gray-400 price-unit"> €/mois</span>
|
| 204 |
+
</div>
|
| 205 |
+
|
| 206 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 207 |
+
Jusqu'à 2 000 Comptes Utilisateurs
|
| 208 |
+
</div>
|
| 209 |
+
|
| 210 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 211 |
+
<li class="flex items-start text-gray-300">
|
| 212 |
+
<svg class="w-5 h-5 text-blue-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 213 |
+
Monitoring et Alertes en Temps Réel
|
| 214 |
+
</li>
|
| 215 |
+
<li class="flex items-start text-gray-300">
|
| 216 |
+
<svg class="w-5 h-5 text-blue-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 217 |
+
Logs API Détaillés (Accès à `/api-logs`)
|
| 218 |
+
</li>
|
| 219 |
+
<li class="flex items-start text-gray-300">
|
| 220 |
+
<svg class="w-5 h-5 text-blue-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 221 |
+
Support Prioritaire (24h)
|
| 222 |
+
</li>
|
| 223 |
+
<li class="flex items-start text-gray-300">
|
| 224 |
+
<svg class="w-5 h-5 text-blue-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 225 |
+
Option de dépassement ($/100 comptes)
|
| 226 |
+
</li>
|
| 227 |
+
</ul>
|
| 228 |
+
|
| 229 |
+
<a href="/checkout?plan=professional_monthly" class="mt-8 block text-center px-6 py-3 bg-blue-600 text-white text-lg font-bold shadow-md hover:bg-blue-700 transition duration-300 plan-button" data-plan="professional">
|
| 230 |
+
Passer au Plan Pro
|
| 231 |
+
</a>
|
| 232 |
+
</div>
|
| 233 |
+
|
| 234 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-red-500 flex flex-col">
|
| 235 |
+
<h2 class="text-2xl font-bold text-red-400 mb-2">Entreprise</h2>
|
| 236 |
+
<p class="text-gray-400 mb-6 text-sm">Solutions haut de gamme et grandes équipes.</p>
|
| 237 |
+
|
| 238 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 239 |
+
<span class="monthly-price" data-price="Sur Devis">Sur Devis</span>
|
| 240 |
+
<span class="annual-price hidden" data-price="Sur Devis">Sur Devis</span>
|
| 241 |
+
<span class="text-xl text-gray-400 price-unit"></span>
|
| 242 |
+
</div>
|
| 243 |
+
|
| 244 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 245 |
+
Comptes Utilisateurs Illimités
|
| 246 |
+
</div>
|
| 247 |
+
|
| 248 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 249 |
+
<li class="flex items-start text-gray-300">
|
| 250 |
+
<svg class="w-5 h-5 text-red-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 251 |
+
Garantie de Niveau de Service (SLA)
|
| 252 |
+
</li>
|
| 253 |
+
<li class="flex items-start text-gray-300">
|
| 254 |
+
<svg class="w-5 h-5 text-red-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 255 |
+
Authentification Unique (SSO)
|
| 256 |
+
</li>
|
| 257 |
+
<li class="flex items-start text-gray-300">
|
| 258 |
+
<svg class="w-5 h-5 text-red-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 259 |
+
Gestion des Accès Privilégiés
|
| 260 |
+
</li>
|
| 261 |
+
<li class="flex items-start text-gray-300">
|
| 262 |
+
<svg class="w-5 h-5 text-red-500 mr-2 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>
|
| 263 |
+
Support Dédicacé 24/7
|
| 264 |
+
</li>
|
| 265 |
+
</ul>
|
| 266 |
+
|
| 267 |
+
<a href="/contact" class="mt-8 block text-center px-6 py-3 bg-red-600 text-white text-lg font-bold shadow-md hover:bg-red-700 transition duration-300 plan-button" data-plan="enterprise">
|
| 268 |
+
Contacter les Ventes
|
| 269 |
+
</a>
|
| 270 |
+
</div>
|
| 271 |
+
</div>
|
| 272 |
+
|
| 273 |
+
</main>
|
| 274 |
+
|
| 275 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 276 |
+
© 2025 Nexus. Tarifs et Plans de Service.
|
| 277 |
+
</footer>
|
| 278 |
+
</div>
|
| 279 |
+
|
| 280 |
+
<script>
|
| 281 |
+
const monthlyBtn = document.getElementById('monthly-btn');
|
| 282 |
+
const annualBtn = document.getElementById('annual-btn');
|
| 283 |
+
const monthlyPrices = document.querySelectorAll('.monthly-price');
|
| 284 |
+
const annualPrices = document.querySelectorAll('.annual-price');
|
| 285 |
+
const priceUnits = document.querySelectorAll('.price-unit');
|
| 286 |
+
const planButtons = document.querySelectorAll('.plan-button'); // Nouveaux boutons
|
| 287 |
+
|
| 288 |
+
// ... (Logique de bascule du mode sombre/clair - inchangée) ...
|
| 289 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 290 |
+
const htmlElement = document.documentElement;
|
| 291 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 292 |
+
|
| 293 |
+
// Charger le thème depuis le localStorage
|
| 294 |
+
const savedTheme = localStorage.getItem('theme');
|
| 295 |
+
if (savedTheme === 'light') {
|
| 296 |
+
htmlElement.classList.remove('dark');
|
| 297 |
+
htmlElement.classList.add('light');
|
| 298 |
+
iconElement.textContent = 'dark_mode';
|
| 299 |
+
} else {
|
| 300 |
+
// Dark mode par défaut si rien n'est sauvegardé ou 'dark'
|
| 301 |
+
htmlElement.classList.add('dark');
|
| 302 |
+
htmlElement.classList.remove('light');
|
| 303 |
+
iconElement.textContent = 'light_mode';
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
themeToggle.addEventListener('click', () => {
|
| 307 |
+
if (htmlElement.classList.contains('light')) {
|
| 308 |
+
htmlElement.classList.remove('light');
|
| 309 |
+
htmlElement.classList.add('dark');
|
| 310 |
+
localStorage.setItem('theme', 'dark');
|
| 311 |
+
iconElement.textContent = 'light_mode';
|
| 312 |
+
} else {
|
| 313 |
+
htmlElement.classList.add('light');
|
| 314 |
+
htmlElement.classList.remove('dark');
|
| 315 |
+
localStorage.setItem('theme', 'light');
|
| 316 |
+
iconElement.textContent = 'dark_mode';
|
| 317 |
+
}
|
| 318 |
+
});
|
| 319 |
+
// ... (Fin de la logique de bascule du mode sombre/clair) ...
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
// Fonction pour mettre à jour l'affichage des tarifs et les liens
|
| 323 |
+
function updatePricing(isAnnual) {
|
| 324 |
+
|
| 325 |
+
const period = isAnnual ? '_annual' : '_monthly';
|
| 326 |
+
const unit = isAnnual ? ' €/an' : ' €/mois';
|
| 327 |
+
|
| 328 |
+
// Mise à jour visuelle des boutons Mensuel/Annuel
|
| 329 |
+
monthlyBtn.classList.remove('bg-blue-600', 'text-white');
|
| 330 |
+
monthlyBtn.classList.add('text-gray-300', 'hover:text-white');
|
| 331 |
+
annualBtn.classList.remove('bg-blue-600', 'text-white');
|
| 332 |
+
annualBtn.classList.add('text-gray-300', 'hover:text-white');
|
| 333 |
+
|
| 334 |
+
if (isAnnual) {
|
| 335 |
+
annualBtn.classList.add('bg-blue-600', 'text-white');
|
| 336 |
+
annualBtn.classList.remove('text-gray-300', 'hover:text-white');
|
| 337 |
+
} else {
|
| 338 |
+
monthlyBtn.classList.add('bg-blue-600', 'text-white');
|
| 339 |
+
monthlyBtn.classList.remove('text-gray-300', 'hover:text-white');
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
// Mise à jour des prix et des unités
|
| 343 |
+
monthlyPrices.forEach(el => el.classList.toggle('hidden', isAnnual));
|
| 344 |
+
annualPrices.forEach(el => el.classList.toggle('hidden', !isAnnual));
|
| 345 |
+
priceUnits.forEach(el => el.textContent = unit);
|
| 346 |
+
|
| 347 |
+
// Le plan développeur est toujours gratuit, mais l'unité change
|
| 348 |
+
document.querySelector('.pricing-grid > div:first-child .price-unit').textContent = unit;
|
| 349 |
+
|
| 350 |
+
// Le plan entreprise est "Sur Devis" sans unité
|
| 351 |
+
document.querySelector('.pricing-grid > div:last-child .price-unit').textContent = '';
|
| 352 |
+
|
| 353 |
+
// Mise à jour des liens des boutons
|
| 354 |
+
planButtons.forEach(button => {
|
| 355 |
+
const planType = button.getAttribute('data-plan');
|
| 356 |
+
if (planType === 'developer') {
|
| 357 |
+
button.setAttribute('href', '/inscription'); // Gratuit, lien inchangé
|
| 358 |
+
} else if (planType === 'enterprise') {
|
| 359 |
+
button.setAttribute('href', '/contact'); // Sur Devis, lien inchangé
|
| 360 |
+
} else {
|
| 361 |
+
button.setAttribute('href', `/checkout?plan=${planType}${period}`);
|
| 362 |
+
}
|
| 363 |
+
});
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
// Événements Tarification
|
| 367 |
+
monthlyBtn.addEventListener('click', () => updatePricing(false));
|
| 368 |
+
annualBtn.addEventListener('click', () => updatePricing(true));
|
| 369 |
+
|
| 370 |
+
// Initialisation Tarification au chargement
|
| 371 |
+
updatePricing(false);
|
| 372 |
+
</script>
|
| 373 |
+
|
| 374 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900" style="background-color: var(--bg-card); border-color: var(--border-color);">
|
| 375 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 376 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 377 |
+
|
| 378 |
+
<div class="col-span-2 lg:col-span-1">
|
| 379 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 380 |
+
<p class="mt-3 text-gray-400">
|
| 381 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 382 |
+
</p>
|
| 383 |
+
<div class="mt-4 flex space-x-4">
|
| 384 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 385 |
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.014 4.85.07c3.275.146 4.47 1.583 4.61 4.85.056 1.266.07 1.646.07 4.85s-.014 3.584-.07 4.85c-.14 3.267-1.335 4.704-4.61 4.85-1.266.056-1.646.07-4.85.07s-3.584-.014-4.85-.07c-3.275-.146-4.47-1.583-4.61-4.85-.056-1.266-.07-1.646-.07-4.85s.014-3.584.07-4.85c.14-3.267 1.335-4.704 4.61-4.85 1.266-.056 1.646-.07 4.85-.07zM12 0c-3.784 0-4.285.016-5.773.083-4.722.211-6.755 2.24-6.965 6.965C.016 7.715 0 8.216 0 12s.016 4.285.083 5.773c.21 4.721 2.239 6.755 6.965 6.965 1.488.067 1.99.083 5.773.083s4.285-.016 5.773-.083c4.721-.21 6.755-2.239 6.965-6.965.067-1.488.083-1.99.083-5.773s-.016-4.285-.083-5.773c-.21-4.722-2.239-6.755-6.965-6.965C16.285.016 15.784 0 12 0zm0 14.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z"/></svg>
|
| 386 |
+
</a>
|
| 387 |
+
</div>
|
| 388 |
+
</div>
|
| 389 |
+
|
| 390 |
+
<div>
|
| 391 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 392 |
+
<ul class="space-y-3 text-gray-400">
|
| 393 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 394 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 395 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 396 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 397 |
+
</ul>
|
| 398 |
+
</div>
|
| 399 |
+
|
| 400 |
+
<div>
|
| 401 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 402 |
+
<ul class="space-y-3 text-gray-400">
|
| 403 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 404 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 405 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 406 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 407 |
+
</ul>
|
| 408 |
+
</div>
|
| 409 |
+
|
| 410 |
+
<div class="col-span-2 md:col-span-1">
|
| 411 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 412 |
+
<ul class="space-y-3 text-gray-400">
|
| 413 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 414 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 415 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 416 |
+
</ul>
|
| 417 |
+
</div>
|
| 418 |
+
|
| 419 |
+
</div>
|
| 420 |
+
|
| 421 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm" style="border-color: var(--border-color);">
|
| 422 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 423 |
+
</div>
|
| 424 |
+
</div>
|
| 425 |
+
</footer>
|
| 426 |
+
|
| 427 |
+
</body>
|
| 428 |
+
</html>
|