Spaces:
Sleeping
Sleeping
Upload 15 files
Browse files- templates/a_propos.html +235 -0
- templates/api_key.html +363 -0
- templates/api_logs.html +282 -0
- templates/conditions_utilisation.html +357 -0
- templates/connexion.html +203 -0
- templates/dashboard.html +268 -0
- templates/documentation.html +285 -0
- templates/index.html +488 -0
- templates/inscription.html +247 -0
- templates/mentions_legales.html +327 -0
- templates/mot_de_passe_oublie.html +238 -0
- templates/politique_confidentialite.html +370 -0
- templates/profile.html +258 -0
- templates/support.html +303 -0
- templates/tarifs.html +401 -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/api_key.html
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>Clés API - Nexus Pro</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 |
+
/* Configuration de la police Inter et thème sombre */
|
| 12 |
+
body { font-family: 'Inter', sans-serif; }
|
| 13 |
+
|
| 14 |
+
/* Style pour les boutons et cartes carrés (Artboard) */
|
| 15 |
+
.btn-square, .card-square {
|
| 16 |
+
border-radius: 0; /* Supprime l'arrondi */
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
/* Styles spécifiques pour le chargement/spinner */
|
| 20 |
+
.spinner {
|
| 21 |
+
border-top-color: var(--spinner-color); /* Utilisation de variable */
|
| 22 |
+
animation: spin 1s linear infinite;
|
| 23 |
+
}
|
| 24 |
+
@keyframes spin {
|
| 25 |
+
to { transform: rotate(360deg); }
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/* Style pour la Sidebar - FIXE et complète (Correction pour la stabilité) */
|
| 29 |
+
.sidebar {
|
| 30 |
+
transition: transform 0.3s ease-in-out;
|
| 31 |
+
transform: translateX(-100%);
|
| 32 |
+
position: fixed;
|
| 33 |
+
top: 0;
|
| 34 |
+
left: 0;
|
| 35 |
+
height: 100vh;
|
| 36 |
+
z-index: 30;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.sidebar.open {
|
| 40 |
+
transform: translateX(0);
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
@media (min-width: 1024px) {
|
| 44 |
+
.sidebar {
|
| 45 |
+
transform: translateX(0) !important;
|
| 46 |
+
/* Utilisation de sticky pour maintenir la barre latérale fixe lors du défilement */
|
| 47 |
+
position: sticky;
|
| 48 |
+
height: 100vh;
|
| 49 |
+
top: 0;
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
</style>
|
| 53 |
+
</head>
|
| 54 |
+
|
| 55 |
+
<body class="bg-gray-900 text-white min-h-screen flex">
|
| 56 |
+
<aside id="sidebar"
|
| 57 |
+
class="sidebar w-64 bg-gray-800 border-r border-gray-700 flex-shrink-0 flex flex-col p-4">
|
| 58 |
+
<h1 class="text-2xl font-bold mb-8 border-b border-gray-700 pb-4 text-blue-400">Nexus Pro</h1>
|
| 59 |
+
<nav class="flex-grow overflow-y-auto">
|
| 60 |
+
<ul class="space-y-2">
|
| 61 |
+
<li>
|
| 62 |
+
<a href="/dashboard"
|
| 63 |
+
class="flex items-center p-3 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white transition duration-200 btn-square">
|
| 64 |
+
<span class="material-symbols-rounded mr-3">dashboard</span>
|
| 65 |
+
Dashboard
|
| 66 |
+
</a>
|
| 67 |
+
</li>
|
| 68 |
+
<li>
|
| 69 |
+
<a href="/profile"
|
| 70 |
+
class="flex items-center p-3 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white transition duration-200 btn-square">
|
| 71 |
+
<span class="material-symbols-rounded mr-3">account_circle</span>
|
| 72 |
+
Profil
|
| 73 |
+
</a>
|
| 74 |
+
</li>
|
| 75 |
+
<li>
|
| 76 |
+
<a href="/api-keys"
|
| 77 |
+
class="flex items-center p-3 text-sm font-medium text-white bg-gray-700 transition duration-200 btn-square">
|
| 78 |
+
<span class="material-symbols-rounded mr-3">key</span>
|
| 79 |
+
Clés API
|
| 80 |
+
</a>
|
| 81 |
+
</li>
|
| 82 |
+
<li>
|
| 83 |
+
<a href="/api-logs"
|
| 84 |
+
class="flex items-center p-3 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white transition duration-200 btn-square">
|
| 85 |
+
<span class="material-symbols-rounded mr-3">history</span>
|
| 86 |
+
Logs API
|
| 87 |
+
</a>
|
| 88 |
+
</li>
|
| 89 |
+
<li class="border-t border-gray-700 my-2 pt-2"></li>
|
| 90 |
+
<li>
|
| 91 |
+
<a href="/documentation"
|
| 92 |
+
class="flex items-center p-3 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white transition duration-200 btn-square">
|
| 93 |
+
<span class="material-symbols-rounded mr-3">article</span>
|
| 94 |
+
Documentation
|
| 95 |
+
</a>
|
| 96 |
+
</li>
|
| 97 |
+
<li>
|
| 98 |
+
<a href="/tarifs"
|
| 99 |
+
class="flex items-center p-3 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white transition duration-200 btn-square">
|
| 100 |
+
<span class="material-symbols-rounded mr-3">payments</span>
|
| 101 |
+
Tarifs
|
| 102 |
+
</a>
|
| 103 |
+
</li>
|
| 104 |
+
<li>
|
| 105 |
+
<a href="/support"
|
| 106 |
+
class="flex items-center p-3 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white transition duration-200 btn-square">
|
| 107 |
+
<span class="material-symbols-rounded mr-3">help</span>
|
| 108 |
+
Support
|
| 109 |
+
</a>
|
| 110 |
+
</li>
|
| 111 |
+
</ul>
|
| 112 |
+
</nav>
|
| 113 |
+
<div class="mt-auto pt-4 border-t border-gray-700">
|
| 114 |
+
<button id="logout-button-sidebar"
|
| 115 |
+
class="flex items-center justify-center w-full p-3 text-sm font-medium text-red-400 hover:bg-red-900/50 transition duration-200 btn-square">
|
| 116 |
+
<span class="material-symbols-rounded mr-3">logout</span>
|
| 117 |
+
Déconnexion
|
| 118 |
+
</button>
|
| 119 |
+
</div>
|
| 120 |
+
</aside>
|
| 121 |
+
|
| 122 |
+
<button id="sidebar-toggle"
|
| 123 |
+
class="lg:hidden fixed top-4 left-4 z-40 p-2 bg-gray-800 text-white rounded-full shadow-lg">
|
| 124 |
+
<span class="material-symbols-rounded">menu</span>
|
| 125 |
+
</button>
|
| 126 |
+
|
| 127 |
+
<main class="flex-grow p-4 lg:p-8">
|
| 128 |
+
<header class="mb-8 flex justify-between items-center">
|
| 129 |
+
<h2 class="text-3xl font-bold text-white">Gestion des Clés API</h2>
|
| 130 |
+
</header>
|
| 131 |
+
|
| 132 |
+
<div id="status-message" class="hidden p-3 mb-4 rounded-md font-medium"></div>
|
| 133 |
+
|
| 134 |
+
<section class="bg-gray-800 p-6 card-square shadow-xl">
|
| 135 |
+
|
| 136 |
+
<div id="key-display-area" class="hidden">
|
| 137 |
+
<h3 class="text-xl font-semibold mb-4 text-white">Votre Clé API Actuelle</h3>
|
| 138 |
+
|
| 139 |
+
<div class="flex flex-col md:flex-row items-stretch md:items-center space-y-4 md:space-y-0 md:space-x-4">
|
| 140 |
+
<div class="flex-grow relative">
|
| 141 |
+
<input type="password" id="api-key-input" readonly
|
| 142 |
+
value="****************************************"
|
| 143 |
+
class="w-full p-4 pr-12 text-sm bg-gray-700 border border-gray-600 focus:border-blue-500 focus:ring-blue-500 text-gray-300 btn-square select-text"
|
| 144 |
+
placeholder="Clé API non générée">
|
| 145 |
+
<button id="toggle-key-visibility"
|
| 146 |
+
class="absolute right-0 top-0 h-full w-12 flex items-center justify-center text-gray-400 hover:text-white transition duration-200">
|
| 147 |
+
<span class="material-symbols-rounded text-xl">visibility</span>
|
| 148 |
+
</button>
|
| 149 |
+
</div>
|
| 150 |
+
|
| 151 |
+
<button id="copy-key-btn"
|
| 152 |
+
class="flex-shrink-0 flex items-center justify-center p-4 bg-blue-600 hover:bg-blue-700 transition duration-200 text-white font-medium btn-square shadow-md">
|
| 153 |
+
<span class="material-symbols-rounded mr-2">content_copy</span>
|
| 154 |
+
Copier
|
| 155 |
+
</button>
|
| 156 |
+
<button id="regenerate-key-btn"
|
| 157 |
+
class="flex-shrink-0 flex items-center justify-center p-4 bg-red-600 hover:bg-red-700 transition duration-200 text-white font-medium btn-square shadow-md">
|
| 158 |
+
<span class="material-symbols-rounded mr-2">refresh</span>
|
| 159 |
+
Régénérer
|
| 160 |
+
</button>
|
| 161 |
+
</div>
|
| 162 |
+
|
| 163 |
+
<p class="mt-4 text-sm text-gray-400">Attention : La régénération invalidera immédiatement votre clé actuelle.</p>
|
| 164 |
+
</div>
|
| 165 |
+
|
| 166 |
+
<div id="initial-creation-area" class="text-center p-8 border-2 border-dashed border-gray-600">
|
| 167 |
+
<h3 class="text-2xl font-semibold mb-3 text-white">Générer votre Clé API</h3>
|
| 168 |
+
<p class="text-gray-400 mb-6">Vous n'avez pas encore de clé API. Générez-la pour commencer à interagir avec nos services.</p>
|
| 169 |
+
<button id="generate-key-btn"
|
| 170 |
+
class="inline-flex items-center justify-center p-4 bg-green-600 hover:bg-green-700 transition duration-200 text-white font-medium btn-square shadow-md">
|
| 171 |
+
<span class="material-symbols-rounded mr-2">vpn_key</span>
|
| 172 |
+
Générer la Clé API
|
| 173 |
+
</button>
|
| 174 |
+
</div>
|
| 175 |
+
|
| 176 |
+
<div id="key-spinner" class="hidden text-center mt-4">
|
| 177 |
+
<div class="spinner w-8 h-8 border-4 border-gray-600 rounded-full mx-auto" style="--spinner-color: #3b82f6;"></div>
|
| 178 |
+
<p class="text-gray-400 mt-2">Chargement ou génération en cours...</p>
|
| 179 |
+
</div>
|
| 180 |
+
|
| 181 |
+
</section>
|
| 182 |
+
|
| 183 |
+
<section class="mt-8">
|
| 184 |
+
<h3 class="text-xl font-bold mb-4">Utilisation de la Clé</h3>
|
| 185 |
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
| 186 |
+
<div class="bg-gray-800 p-6 card-square">
|
| 187 |
+
<h4 class="font-semibold mb-3 text-blue-400">Méthode 1 : En-tête HTTP (Recommandée)</h4>
|
| 188 |
+
<p class="text-gray-400 mb-4 text-sm">Transmettez votre clé via l'en-tête `X-User-API-Key` pour des raisons de sécurité et de standardisation.</p>
|
| 189 |
+
<div class="bg-gray-900 p-3 text-sm overflow-x-auto">
|
| 190 |
+
<code class="text-green-400">X-User-API-Key: VOTRE_CLE_API</code>
|
| 191 |
+
</div>
|
| 192 |
+
</div>
|
| 193 |
+
<div class="bg-gray-800 p-6 card-square">
|
| 194 |
+
<h4 class="font-semibold mb-3 text-blue-400">Méthode 2 : Paramètre d'URL (Simple)</h4>
|
| 195 |
+
<p class="text-gray-400 mb-4 text-sm">Utilisez le paramètre `api_key` pour les requêtes simples ou les tests.</p>
|
| 196 |
+
<div class="bg-gray-900 p-3 text-sm overflow-x-auto">
|
| 197 |
+
<code class="text-green-400">/api/endpoint?api_key=VOTRE_CLE_API</code>
|
| 198 |
+
</div>
|
| 199 |
+
</div>
|
| 200 |
+
</div>
|
| 201 |
+
</section>
|
| 202 |
+
|
| 203 |
+
</main>
|
| 204 |
+
|
| 205 |
+
<script>
|
| 206 |
+
// 1. Déclaration des éléments du DOM
|
| 207 |
+
const sidebar = document.getElementById('sidebar');
|
| 208 |
+
const sidebarToggle = document.getElementById('sidebar-toggle');
|
| 209 |
+
const keyDisplayArea = document.getElementById('key-display-area');
|
| 210 |
+
const initialCreationArea = document.getElementById('initial-creation-area');
|
| 211 |
+
const keyInput = document.getElementById('api-key-input');
|
| 212 |
+
const generateBtn = document.getElementById('generate-key-btn');
|
| 213 |
+
const regenerateBtn = document.getElementById('regenerate-key-btn');
|
| 214 |
+
const copyBtn = document.getElementById('copy-key-btn');
|
| 215 |
+
const toggleVisibilityBtn = document.getElementById('toggle-key-visibility');
|
| 216 |
+
const statusMessage = document.getElementById('status-message');
|
| 217 |
+
const spinner = document.getElementById('key-spinner');
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
// 2. Fonctions utilitaires
|
| 221 |
+
const showStatus = (message, isError = false) => {
|
| 222 |
+
statusMessage.textContent = message;
|
| 223 |
+
statusMessage.className = `p-3 mb-4 rounded-md font-medium ${isError ? 'bg-red-900 text-red-300' : 'bg-green-900 text-green-300'}`;
|
| 224 |
+
statusMessage.classList.remove('hidden');
|
| 225 |
+
};
|
| 226 |
+
|
| 227 |
+
toggleVisibilityBtn.addEventListener('click', () => {
|
| 228 |
+
const icon = toggleVisibilityBtn.querySelector('.material-symbols-rounded');
|
| 229 |
+
if (keyInput.type === 'password') {
|
| 230 |
+
keyInput.type = 'text';
|
| 231 |
+
icon.textContent = 'visibility_off';
|
| 232 |
+
} else {
|
| 233 |
+
keyInput.type = 'password';
|
| 234 |
+
icon.textContent = 'visibility';
|
| 235 |
+
}
|
| 236 |
+
});
|
| 237 |
+
|
| 238 |
+
copyBtn.addEventListener('click', () => {
|
| 239 |
+
const originalType = keyInput.type;
|
| 240 |
+
keyInput.type = 'text';
|
| 241 |
+
keyInput.select();
|
| 242 |
+
keyInput.setSelectionRange(0, 99999);
|
| 243 |
+
document.execCommand('copy');
|
| 244 |
+
keyInput.type = originalType;
|
| 245 |
+
showStatus('Clé API copiée dans le presse-papiers.', false);
|
| 246 |
+
});
|
| 247 |
+
|
| 248 |
+
// 3. Logique d'affichage
|
| 249 |
+
const updateKeyDisplay = (apiKey) => {
|
| 250 |
+
if (apiKey) {
|
| 251 |
+
keyInput.value = apiKey;
|
| 252 |
+
keyInput.type = 'password';
|
| 253 |
+
toggleVisibilityBtn.querySelector('.material-symbols-rounded').textContent = 'visibility';
|
| 254 |
+
keyDisplayArea.classList.remove('hidden');
|
| 255 |
+
initialCreationArea.classList.add('hidden');
|
| 256 |
+
} else {
|
| 257 |
+
keyInput.value = 'Clé API non générée';
|
| 258 |
+
keyInput.type = 'password';
|
| 259 |
+
keyDisplayArea.classList.add('hidden');
|
| 260 |
+
initialCreationArea.classList.remove('hidden');
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
// 4. Récupération de l'état de la clé
|
| 265 |
+
const fetchApiKey = async () => {
|
| 266 |
+
statusMessage.classList.add('hidden');
|
| 267 |
+
spinner.classList.remove('hidden');
|
| 268 |
+
|
| 269 |
+
try {
|
| 270 |
+
// Appel à la route proxy /api/user/info pour obtenir les infos, y compris la clé.
|
| 271 |
+
const response = await fetch('/api/user/info', {
|
| 272 |
+
method: 'GET',
|
| 273 |
+
headers: { 'Content-Type': 'application/json' }
|
| 274 |
+
});
|
| 275 |
+
|
| 276 |
+
const data = await response.json();
|
| 277 |
+
|
| 278 |
+
if (data.status === 'Success') {
|
| 279 |
+
// L'API Nexus est censée retourner 'api_key' dans le profil
|
| 280 |
+
const apiKey = data.api_key || null;
|
| 281 |
+
updateKeyDisplay(apiKey);
|
| 282 |
+
|
| 283 |
+
} else if (response.status === 401) {
|
| 284 |
+
window.location.href = '/connexion';
|
| 285 |
+
} else {
|
| 286 |
+
console.error('Erreur lors de la récupération des données utilisateur:', data.message);
|
| 287 |
+
showStatus("Erreur: Impossible de vérifier le statut de la clé API.", true);
|
| 288 |
+
updateKeyDisplay(null);
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
} catch (error) {
|
| 292 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 293 |
+
showStatus("Erreur: Impossible de contacter le serveur Flask.", true);
|
| 294 |
+
updateKeyDisplay(null);
|
| 295 |
+
} finally {
|
| 296 |
+
spinner.classList.add('hidden');
|
| 297 |
+
}
|
| 298 |
+
};
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
// 5. Génération/Régénération de la clé (generateApiKey)
|
| 302 |
+
const generateApiKey = async () => {
|
| 303 |
+
statusMessage.classList.add('hidden');
|
| 304 |
+
spinner.classList.remove('hidden');
|
| 305 |
+
keyInput.value = 'Génération...';
|
| 306 |
+
|
| 307 |
+
try {
|
| 308 |
+
// *** CORRIGÉ *** : L'URL correspond maintenant à la route dans user_routes.py (/api/user/generate-key)
|
| 309 |
+
const response = await fetch('/api/user/generate-key', {
|
| 310 |
+
method: 'POST',
|
| 311 |
+
headers: { 'Content-Type': 'application/json' }
|
| 312 |
+
});
|
| 313 |
+
|
| 314 |
+
const data = await response.json();
|
| 315 |
+
|
| 316 |
+
if (data.status === 'Success' && data.api_key) {
|
| 317 |
+
updateKeyDisplay(data.api_key);
|
| 318 |
+
showStatus("Nouvelle clé API générée avec succès ! Veuillez la copier.", false);
|
| 319 |
+
} else {
|
| 320 |
+
console.error('Échec de la génération de clé:', data.message);
|
| 321 |
+
showStatus(`Échec de la génération: ${data.message}`, true);
|
| 322 |
+
fetchApiKey();
|
| 323 |
+
}
|
| 324 |
+
} catch (error) {
|
| 325 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 326 |
+
showStatus("Erreur: Impossible de contacter le serveur pour générer la clé.", true);
|
| 327 |
+
} finally {
|
| 328 |
+
spinner.classList.add('hidden');
|
| 329 |
+
}
|
| 330 |
+
};
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
// 6. Événements et Initialisation
|
| 334 |
+
|
| 335 |
+
generateBtn.addEventListener('click', generateApiKey);
|
| 336 |
+
regenerateBtn.addEventListener('click', generateApiKey);
|
| 337 |
+
|
| 338 |
+
window.addEventListener('load', fetchApiKey);
|
| 339 |
+
|
| 340 |
+
// Logique de Déconnexion
|
| 341 |
+
const logoutHandler = async (e) => {
|
| 342 |
+
e.preventDefault();
|
| 343 |
+
const response = await fetch('/api/logout', { // Utilise /api/logout qui est gérée dans app.py
|
| 344 |
+
method: 'POST',
|
| 345 |
+
headers: { 'Content-Type': 'application/json' }
|
| 346 |
+
});
|
| 347 |
+
|
| 348 |
+
const data = await response.json();
|
| 349 |
+
if (data.status === 'Success' && data.redirect) {
|
| 350 |
+
window.location.href = data.redirect;
|
| 351 |
+
} else {
|
| 352 |
+
alert('Erreur lors de la déconnexion.');
|
| 353 |
+
}
|
| 354 |
+
};
|
| 355 |
+
document.getElementById('logout-button-sidebar').addEventListener('click', logoutHandler);
|
| 356 |
+
|
| 357 |
+
// Logique de la Sidebar sur mobile
|
| 358 |
+
sidebarToggle.addEventListener('click', () => {
|
| 359 |
+
sidebar.classList.toggle('open');
|
| 360 |
+
});
|
| 361 |
+
</script>
|
| 362 |
+
</body>
|
| 363 |
+
</html>
|
templates/api_logs.html
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>Logs API - Nexus Pro</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 |
+
/* Appliquer les variables de thème */
|
| 14 |
+
background-color: var(--bg-color);
|
| 15 |
+
color: var(--text-color-primary); /* Utilisation de la variable primaire pour le texte du body */
|
| 16 |
+
transition: background-color 0.3s, color 0.3s; /* Transition pour un effet doux */
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
/* Étape 2 : Définir les Styles (CSS) - Variables de Thème */
|
| 20 |
+
/* Mode Sombre (par défaut - noir très foncé) */
|
| 21 |
+
:root, .dark {
|
| 22 |
+
--bg-color: #0A0A0A; /* Noir très foncé (pour body, header, footer) */
|
| 23 |
+
--bg-card: #1C1C1C; /* Fond des cartes/panneaux */
|
| 24 |
+
--text-color-primary: #E3E3E3; /* Texte principal (ancien text-white) */
|
| 25 |
+
--text-color-secondary: #A0A0A0; /* Texte secondaire (pour gray-400/500) */
|
| 26 |
+
--primary-color: #3B82F6; /* blue-500 par défaut */
|
| 27 |
+
--border-color: #4B5563; /* gray-600 */
|
| 28 |
+
--border-card-divide: #374151; /* gray-700 pour les séparations dans les cartes */
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Mode Clair */
|
| 32 |
+
html.light {
|
| 33 |
+
--bg-color: #F8F8F8;
|
| 34 |
+
--bg-card: #FFFFFF;
|
| 35 |
+
--text-color-primary: #1F2937; /* Texte principal (gray-800) */
|
| 36 |
+
--text-color-secondary: #6B7280; /* Texte secondaire (gray-500) */
|
| 37 |
+
--primary-color: #1D4ED8; /* blue-700 */
|
| 38 |
+
--border-color: #D1D5DB; /* gray-300 */
|
| 39 |
+
--border-card-divide: #E5E7EB; /* gray-200 pour les séparations dans les cartes */
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
/* Mappage des classes Tailwind aux variables de thème pour le mode sombre/clair */
|
| 43 |
+
/* Modification pour que le header et les footers utilisent --bg-color */
|
| 44 |
+
.bg-gray-900 { background-color: var(--bg-color); }
|
| 45 |
+
/* Modification pour que les cartes et le panneau de logs utilisent --bg-card */
|
| 46 |
+
.bg-gray-800 { background-color: var(--bg-card); }
|
| 47 |
+
|
| 48 |
+
/* Mappage des couleurs de texte pour le mode sombre/clair */
|
| 49 |
+
.text-white { color: var(--text-color-primary); }
|
| 50 |
+
/* Pour les textes dans les cartes et le footer qui utilisaient des nuances de gris */
|
| 51 |
+
.text-gray-300 { color: var(--text-color-primary); }
|
| 52 |
+
.text-gray-400 { color: var(--text-color-secondary); }
|
| 53 |
+
.text-gray-500 { color: var(--text-color-secondary); opacity: 0.9; } /* Ajustement léger pour les nuances */
|
| 54 |
+
|
| 55 |
+
.border-blue-500\/50 { border-color: var(--primary-color); }
|
| 56 |
+
.text-blue-500 { color: var(--primary-color); }
|
| 57 |
+
.hover\:text-blue-300:hover { color: var(--primary-color); }
|
| 58 |
+
.border-l-4 { border-color: var(--primary-color); }
|
| 59 |
+
.border-t-2 { border-color: var(--primary-color); } /* Ajustement pour un meilleur contraste en mode clair */
|
| 60 |
+
.border-b { border-color: var(--border-color); }
|
| 61 |
+
.divide-y { border-color: var(--border-color); }
|
| 62 |
+
/* Pour les séparateurs dans la table des logs */
|
| 63 |
+
.border-gray-700 { border-color: var(--border-card-divide); }
|
| 64 |
+
.divide-gray-700 { border-color: var(--border-card-divide); }
|
| 65 |
+
.border-gray-800 { border-color: var(--border-card-divide); } /* Utilisé dans le footer */
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
/* Classe pour la barre de navigation fixe (stable) */
|
| 69 |
+
.header-fixed {
|
| 70 |
+
position: fixed;
|
| 71 |
+
top: 0;
|
| 72 |
+
left: 0;
|
| 73 |
+
right: 0;
|
| 74 |
+
z-index: 50;
|
| 75 |
+
/* Suppression des marges pour un aspect moins haut, tout en restant responsive */
|
| 76 |
+
padding-top: 1rem;
|
| 77 |
+
padding-bottom: 1rem;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
</style>
|
| 81 |
+
</head>
|
| 82 |
+
<body class="min-h-screen pt-20"> <div class="container mx-auto p-4 sm:p-6 lg:p-8">
|
| 83 |
+
|
| 84 |
+
<header class="header-fixed bg-gray-900 text-white flex flex-col sm:flex-row justify-between items-center px-4 sm:px-6 lg:px-8 border-b border-blue-500/50">
|
| 85 |
+
<h1 class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 86 |
+
Historique des Logs API
|
| 87 |
+
</h1>
|
| 88 |
+
<nav class="flex items-center space-x-4">
|
| 89 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 90 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 91 |
+
</button>
|
| 92 |
+
<a href="/dashboard" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 93 |
+
Dashboard
|
| 94 |
+
</a>
|
| 95 |
+
<a href="/profile" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 96 |
+
Profil
|
| 97 |
+
</a>
|
| 98 |
+
<button id="logout-button" class="px-4 py-2 bg-red-600 hover:bg-red-700 transition duration-200 font-medium shadow-md">
|
| 99 |
+
Déconnexion
|
| 100 |
+
</button>
|
| 101 |
+
</nav>
|
| 102 |
+
</header>
|
| 103 |
+
|
| 104 |
+
<main class="space-y-8 mt-4">
|
| 105 |
+
|
| 106 |
+
<div class="p-6 bg-gray-800 shadow-2xl border-l-4 border-blue-500">
|
| 107 |
+
<h2 class="text-3xl font-bold text-blue-500 mb-2">Statistiques d'Utilisation</h2>
|
| 108 |
+
<p class="text-lg text-gray-300">
|
| 109 |
+
ID Utilisateur Connecté: <strong class="text-white">{{ user_id }}</strong>
|
| 110 |
+
</p>
|
| 111 |
+
</div>
|
| 112 |
+
|
| 113 |
+
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
| 114 |
+
<div class="p-5 bg-gray-800 shadow-xl border-t-2 border-green-500 text-center">
|
| 115 |
+
<p class="text-4xl font-bold text-green-400" id="requestsCount">--</p>
|
| 116 |
+
<p class="text-gray-400 mt-1">Requêtes (30 jours)</p>
|
| 117 |
+
</div>
|
| 118 |
+
<div class="p-5 bg-gray-800 shadow-xl border-t-2 border-yellow-500 text-center">
|
| 119 |
+
<p class="text-4xl font-bold text-yellow-400" id="errorsCount">--</p>
|
| 120 |
+
<p class="text-gray-400 mt-1">Erreurs 5xx (30 jours)</p>
|
| 121 |
+
</div>
|
| 122 |
+
<div class="p-5 bg-gray-800 shadow-xl border-t-2 border-purple-500 text-center">
|
| 123 |
+
<p class="text-4xl font-bold text-purple-400" id="lastActivity">--</p>
|
| 124 |
+
<p class="text-gray-400 mt-1">Dernière Activité</p>
|
| 125 |
+
</div>
|
| 126 |
+
</div>
|
| 127 |
+
|
| 128 |
+
<div class="bg-gray-800 shadow-xl overflow-x-auto">
|
| 129 |
+
<h3 class="text-2xl font-semibold text-white p-6 border-b border-gray-700">Logs Récents</h3>
|
| 130 |
+
<table class="min-w-full divide-y divide-gray-700">
|
| 131 |
+
<thead>
|
| 132 |
+
<tr>
|
| 133 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Date/Heure</th>
|
| 134 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Méthode</th>
|
| 135 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Endpoint</th>
|
| 136 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Statut</th>
|
| 137 |
+
</tr>
|
| 138 |
+
</thead>
|
| 139 |
+
<tbody class="divide-y divide-gray-700" id="logsTableBody">
|
| 140 |
+
<tr class="text-gray-300">
|
| 141 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm">2024-10-14 10:30:00</td>
|
| 142 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="bg-green-600/20 text-green-400 px-2 py-0.5 text-xs font-semibold">GET</span></td>
|
| 143 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm">/api/data/fetch</td>
|
| 144 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="bg-green-600/20 text-green-400 px-2 py-0.5 text-xs font-semibold">200</span></td>
|
| 145 |
+
</tr>
|
| 146 |
+
<tr class="text-gray-300">
|
| 147 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm">2024-10-14 10:29:55</td>
|
| 148 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="bg-red-600/20 text-red-400 px-2 py-0.5 text-xs font-semibold">POST</span></td>
|
| 149 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm">/api/user/update</td>
|
| 150 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="bg-red-600/20 text-red-400 px-2 py-0.5 text-xs font-semibold">401</span></td>
|
| 151 |
+
</tr>
|
| 152 |
+
<tr class="text-gray-300">
|
| 153 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm">2024-10-14 10:29:01</td>
|
| 154 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="bg-green-600/20 text-green-400 px-2 py-0.5 text-xs font-semibold">GET</span></td>
|
| 155 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm">/api/status</td>
|
| 156 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm"><span class="bg-green-600/20 text-green-400 px-2 py-0.5 text-xs font-semibold">200</span></td>
|
| 157 |
+
</tr>
|
| 158 |
+
</tbody>
|
| 159 |
+
</table>
|
| 160 |
+
</div>
|
| 161 |
+
|
| 162 |
+
<p class="text-sm text-gray-500 text-center">
|
| 163 |
+
*Ceci est un exemple. L'intégration finale nécessitera un appel à l'API Nexus (`GET /api/logs/{{ user_id }}`).
|
| 164 |
+
</p>
|
| 165 |
+
|
| 166 |
+
</main>
|
| 167 |
+
|
| 168 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 169 |
+
© 2024 Nexus. Tous droits réservés. | Espace Sécurisé
|
| 170 |
+
</footer>
|
| 171 |
+
</div>
|
| 172 |
+
|
| 173 |
+
<script>
|
| 174 |
+
document.getElementById('logout-button').addEventListener('click', async () => {
|
| 175 |
+
const response = await fetch('/logout', { method: 'POST' });
|
| 176 |
+
const data = await response.json();
|
| 177 |
+
if (data.status === 'Success' && data.redirect) {
|
| 178 |
+
window.location.href = data.redirect;
|
| 179 |
+
} else {
|
| 180 |
+
console.error("Erreur lors de la déconnexion.");
|
| 181 |
+
}
|
| 182 |
+
});
|
| 183 |
+
|
| 184 |
+
// Simuler le chargement des statistiques
|
| 185 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 186 |
+
document.getElementById('requestsCount').textContent = '1248';
|
| 187 |
+
document.getElementById('errorsCount').textContent = '12';
|
| 188 |
+
document.getElementById('lastActivity').textContent = 'Il y a 5 min';
|
| 189 |
+
});
|
| 190 |
+
|
| 191 |
+
/* Logique de bascule du mode sombre/clair */
|
| 192 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 193 |
+
const htmlElement = document.documentElement;
|
| 194 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 195 |
+
|
| 196 |
+
// Charger le thème depuis le localStorage
|
| 197 |
+
const savedTheme = localStorage.getItem('theme');
|
| 198 |
+
|
| 199 |
+
// Si le thème est sauvegardé, l'appliquer. Sinon, laisser le thème sombre par défaut.
|
| 200 |
+
if (savedTheme === 'light') {
|
| 201 |
+
htmlElement.classList.add('light');
|
| 202 |
+
htmlElement.classList.remove('dark');
|
| 203 |
+
iconElement.textContent = 'dark_mode';
|
| 204 |
+
} else {
|
| 205 |
+
// S'assurer que le mode sombre est appliqué si non light
|
| 206 |
+
htmlElement.classList.add('dark');
|
| 207 |
+
htmlElement.classList.remove('light');
|
| 208 |
+
iconElement.textContent = 'light_mode';
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
themeToggle.addEventListener('click', () => {
|
| 212 |
+
if (htmlElement.classList.contains('light')) {
|
| 213 |
+
htmlElement.classList.remove('light');
|
| 214 |
+
htmlElement.classList.add('dark');
|
| 215 |
+
localStorage.setItem('theme', 'dark');
|
| 216 |
+
iconElement.textContent = 'light_mode';
|
| 217 |
+
} else {
|
| 218 |
+
htmlElement.classList.add('light');
|
| 219 |
+
htmlElement.classList.remove('dark');
|
| 220 |
+
localStorage.setItem('theme', 'light');
|
| 221 |
+
iconElement.textContent = 'dark_mode';
|
| 222 |
+
}
|
| 223 |
+
});
|
| 224 |
+
/* Fin Logique Mode Sombre/Clair */
|
| 225 |
+
|
| 226 |
+
</script>
|
| 227 |
+
|
| 228 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900">
|
| 229 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 230 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 231 |
+
|
| 232 |
+
<div class="col-span-2 lg:col-span-1">
|
| 233 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 234 |
+
<p class="mt-3 text-gray-400">
|
| 235 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 236 |
+
</p>
|
| 237 |
+
<div class="mt-4 flex space-x-4">
|
| 238 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 239 |
+
<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>
|
| 240 |
+
</a>
|
| 241 |
+
</div>
|
| 242 |
+
</div>
|
| 243 |
+
|
| 244 |
+
<div>
|
| 245 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 246 |
+
<ul class="space-y-3 text-gray-400">
|
| 247 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 248 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 249 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 250 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 251 |
+
</ul>
|
| 252 |
+
</div>
|
| 253 |
+
|
| 254 |
+
<div>
|
| 255 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 256 |
+
<ul class="space-y-3 text-gray-400">
|
| 257 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 258 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 259 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 260 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 261 |
+
</ul>
|
| 262 |
+
</div>
|
| 263 |
+
|
| 264 |
+
<div class="col-span-2 md:col-span-1">
|
| 265 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 266 |
+
<ul class="space-y-3 text-gray-400">
|
| 267 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 268 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 269 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 270 |
+
</ul>
|
| 271 |
+
</div>
|
| 272 |
+
|
| 273 |
+
</div>
|
| 274 |
+
|
| 275 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm">
|
| 276 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
</footer>
|
| 280 |
+
|
| 281 |
+
</body>
|
| 282 |
+
</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/dashboard.html
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>Dashboard - Nexus Pro</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<style>
|
| 9 |
+
/* Configuration de la police Inter et thème sombre */
|
| 10 |
+
body { font-family: 'Inter', sans-serif; }
|
| 11 |
+
|
| 12 |
+
/* Style pour les boutons et cartes carrés (Artboard) */
|
| 13 |
+
.btn-square, .card-square {
|
| 14 |
+
border-radius: 0; /* Supprime l'arrondi */
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Style pour la Sidebar (masquée sur mobile, visible sur Lg+) */
|
| 18 |
+
.sidebar {
|
| 19 |
+
transition: transform 0.3s ease-in-out;
|
| 20 |
+
transform: translateX(-100%);
|
| 21 |
+
/* Fixe la sidebar sur mobile pour qu'elle s'ouvre au-dessus du contenu */
|
| 22 |
+
position: fixed;
|
| 23 |
+
z-index: 30;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
.sidebar.open {
|
| 27 |
+
transform: translateX(0);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
/* Sur les grands écrans, la sidebar est statique et toujours visible */
|
| 31 |
+
@media (min-width: 1024px) {
|
| 32 |
+
.sidebar {
|
| 33 |
+
transform: translateX(0) !important;
|
| 34 |
+
position: relative;
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/* ======================================================= */
|
| 39 |
+
/* Étape 2: Définir les Styles (CSS) - Variables de Thème */
|
| 40 |
+
/* ======================================================= */
|
| 41 |
+
|
| 42 |
+
/* Mode Sombre (Défaut - Noir très foncé) */
|
| 43 |
+
:root {
|
| 44 |
+
--bg-body: #0f0f0f;
|
| 45 |
+
--bg-sidebar-card: #1f1f1f;
|
| 46 |
+
--bg-item-hover: #2a2a2a;
|
| 47 |
+
--text-primary: #E3E3E3;
|
| 48 |
+
--text-secondary: #A0A0A0; /* Correspond à gray-400 */
|
| 49 |
+
--border-color: #333333; /* Correspond à gray-700 */
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
/* Mode Clair */
|
| 53 |
+
html.light {
|
| 54 |
+
--bg-body: #F5F5F5;
|
| 55 |
+
--bg-sidebar-card: #FFFFFF;
|
| 56 |
+
--bg-item-hover: #EBEBEB;
|
| 57 |
+
--text-primary: #1F1F1F;
|
| 58 |
+
--text-secondary: #6B7280; /* Correspond à gray-500 */
|
| 59 |
+
--border-color: #D1D5DB; /* Correspond à gray-300 */
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/* Application des Variables pour la transition */
|
| 63 |
+
body {
|
| 64 |
+
background-color: var(--bg-body);
|
| 65 |
+
color: var(--text-primary);
|
| 66 |
+
transition: background-color 0.3s, color 0.3s;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
/* Sidebar et Cartes (bg-gray-800 remplacé par --bg-sidebar-card) */
|
| 70 |
+
.sidebar, .card-square {
|
| 71 |
+
background-color: var(--bg-sidebar-card);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
/* Items (bg-gray-900 remplacé par --bg-body) */
|
| 75 |
+
.p-4.bg-gray-900 {
|
| 76 |
+
background-color: var(--bg-body) !important;
|
| 77 |
+
}
|
| 78 |
+
.p-3.bg-gray-900 {
|
| 79 |
+
background-color: var(--bg-body) !important;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
/* Texte et bordures standards */
|
| 83 |
+
.text-gray-400 { color: var(--text-secondary) !important; }
|
| 84 |
+
.text-gray-200 { color: var(--text-primary) !important; }
|
| 85 |
+
.border-gray-700 { border-color: var(--border-color) !important; }
|
| 86 |
+
.border-gray-700:hover { border-color: var(--border-color) !important; }
|
| 87 |
+
.border-t-4 { border-top-color: var(--border-color) !important; }
|
| 88 |
+
|
| 89 |
+
/* Application du hover sur les liens de navigation */
|
| 90 |
+
.sidebar nav a:not(.bg-blue-600):hover {
|
| 91 |
+
background-color: var(--bg-item-hover) !important;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
/* Style du bouton de thème (Theme Toggle Button) */
|
| 95 |
+
#theme-toggle {
|
| 96 |
+
background: none;
|
| 97 |
+
border: none;
|
| 98 |
+
cursor: pointer;
|
| 99 |
+
color: var(--text-primary);
|
| 100 |
+
font-size: 24px;
|
| 101 |
+
transition: color 0.2s;
|
| 102 |
+
padding: 8px;
|
| 103 |
+
line-height: 1; /* Assure que l'icône est bien centrée */
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
</style>
|
| 107 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
| 108 |
+
<link rel="stylesheet"
|
| 109 |
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
|
| 110 |
+
</head>
|
| 111 |
+
<body class="min-h-screen">
|
| 112 |
+
|
| 113 |
+
<div class="flex min-h-screen">
|
| 114 |
+
<aside id="sidebar" class="sidebar flex-shrink-0 w-64 border-r border-blue-500/50 p-4 lg:block">
|
| 115 |
+
<h2 class="text-3xl font-extrabold text-blue-500 mb-8 tracking-wider">NEXUS</h2>
|
| 116 |
+
<nav class="space-y-3">
|
| 117 |
+
<a href="/dashboard" class="flex items-center w-full px-4 py-3 bg-blue-600 text-white hover:bg-blue-700 font-bold transition duration-200 btn-square shadow-lg border-2 border-blue-500">
|
| 118 |
+
<i class="fas fa-home w-5 mr-3"></i>
|
| 119 |
+
Dashboard
|
| 120 |
+
</a>
|
| 121 |
+
|
| 122 |
+
<a href="/api-keys" class="flex items-center w-full px-4 py-3 hover:text-blue-400 font-medium transition duration-200 btn-square shadow-lg border hover:border-blue-500">
|
| 123 |
+
<i class="fas fa-key w-5 mr-3"></i>
|
| 124 |
+
Clés API
|
| 125 |
+
</a>
|
| 126 |
+
|
| 127 |
+
<a href="/profile" class="flex items-center w-full px-4 py-3 hover:text-blue-400 font-medium transition duration-200 btn-square shadow-lg border hover:border-blue-500">
|
| 128 |
+
<i class="fas fa-user-circle w-5 mr-3"></i>
|
| 129 |
+
Mon Profil
|
| 130 |
+
</a>
|
| 131 |
+
|
| 132 |
+
<a href="/documentation" class="flex items-center w-full px-4 py-3 hover:text-blue-400 font-medium transition duration-200 btn-square shadow-lg border hover:border-blue-500">
|
| 133 |
+
<i class="fas fa-book w-5 mr-3"></i>
|
| 134 |
+
Documentation
|
| 135 |
+
</a>
|
| 136 |
+
|
| 137 |
+
<a href="/support" class="flex items-center w-full px-4 py-3 hover:text-blue-400 font-medium transition duration-200 btn-square shadow-lg border hover:border-blue-500">
|
| 138 |
+
<i class="fas fa-life-ring w-5 mr-3"></i>
|
| 139 |
+
Centre d'Aide
|
| 140 |
+
</a>
|
| 141 |
+
|
| 142 |
+
</nav>
|
| 143 |
+
|
| 144 |
+
<div class="mt-8 pt-4 border-t border-gray-700">
|
| 145 |
+
<button id="logout-button-sidebar" class="flex items-center w-full px-4 py-3 bg-red-700 text-white hover:bg-red-800 font-medium transition duration-200 btn-square shadow-lg border border-red-500">
|
| 146 |
+
<i class="fas fa-sign-out-alt w-5 mr-3"></i>
|
| 147 |
+
Déconnexion
|
| 148 |
+
</button>
|
| 149 |
+
</div>
|
| 150 |
+
</aside>
|
| 151 |
+
|
| 152 |
+
<div class="flex-grow p-4 sm:p-6 lg:p-8">
|
| 153 |
+
<header class="flex flex-col sm:flex-row justify-between items-center py-4 border-b border-blue-500/50 mb-8">
|
| 154 |
+
<h1 class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 155 |
+
Dashboard
|
| 156 |
+
</h1>
|
| 157 |
+
<div class="flex items-center space-x-4">
|
| 158 |
+
<button id="theme-toggle" aria-label="Basculer le thème">
|
| 159 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 160 |
+
</button>
|
| 161 |
+
<span class="text-sm text-gray-400 hidden md:block">
|
| 162 |
+
ID Utilisateur : <strong class="text-white">{{ user_id }}</strong>
|
| 163 |
+
</span>
|
| 164 |
+
<button id="menu-button" class="lg:hidden p-3 text-white bg-blue-600 hover:bg-blue-700 transition duration-200 btn-square">
|
| 165 |
+
<i class="fas fa-bars w-5 h-5"></i>
|
| 166 |
+
</button>
|
| 167 |
+
</div>
|
| 168 |
+
</header>
|
| 169 |
+
|
| 170 |
+
<main class="space-y-8">
|
| 171 |
+
<div class="card-square p-6 shadow-xl border-t-4 border-blue-500">
|
| 172 |
+
<h2 class="text-2xl font-semibold mb-4 text-blue-400">Statistiques Clés</h2>
|
| 173 |
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
| 174 |
+
<div class="p-4 border btn-square">
|
| 175 |
+
<p class="text-sm text-gray-400">Requêtes du Mois</p>
|
| 176 |
+
<p class="text-3xl font-bold mt-1 text-white">45,678</p>
|
| 177 |
+
</div>
|
| 178 |
+
<div class="p-4 border btn-square">
|
| 179 |
+
<p class="text-sm text-gray-400">Latence Moyenne (ms)</p>
|
| 180 |
+
<p class="text-3xl font-bold mt-1 text-white">85ms</p>
|
| 181 |
+
</div>
|
| 182 |
+
<div class="p-4 border btn-square">
|
| 183 |
+
<p class="text-sm text-gray-400">Taux de Succès</p>
|
| 184 |
+
<p class="text-3xl font-bold mt-1 text-green-500">99.9%</p>
|
| 185 |
+
</div>
|
| 186 |
+
</div>
|
| 187 |
+
</div>
|
| 188 |
+
|
| 189 |
+
<div class="card-square p-6 shadow-xl border-t-4 border-teal-500">
|
| 190 |
+
<h2 class="text-2xl font-semibold mb-4 text-teal-400">Dernières Activités</h2>
|
| 191 |
+
<ul class="space-y-3 text-gray-400">
|
| 192 |
+
<li class="p-3 border btn-square flex justify-between">
|
| 193 |
+
<span>[2024-10-15 10:30] Clé API Regénérée.</span>
|
| 194 |
+
<span class="text-teal-400">Sécurité</span>
|
| 195 |
+
</li>
|
| 196 |
+
<li class="p-3 border btn-square flex justify-between">
|
| 197 |
+
<span>[2024-10-15 10:25] Connexion réussie.</span>
|
| 198 |
+
<span class="text-green-400">Auth</span>
|
| 199 |
+
</li>
|
| 200 |
+
</ul>
|
| 201 |
+
</div>
|
| 202 |
+
</main>
|
| 203 |
+
|
| 204 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 205 |
+
© 2024 Nexus. Tous droits réservés. | Espace Sécurisé
|
| 206 |
+
</footer>
|
| 207 |
+
</div>
|
| 208 |
+
</div>
|
| 209 |
+
|
| 210 |
+
<script>
|
| 211 |
+
// ... (Existing Sidebar and Theme Toggle Logic) ...
|
| 212 |
+
|
| 213 |
+
// 1.3. Logique de Déconnexion
|
| 214 |
+
const logoutHandler = async (e) => {
|
| 215 |
+
e.preventDefault();
|
| 216 |
+
const response = await fetch('/logout', {
|
| 217 |
+
method: 'POST',
|
| 218 |
+
headers: { 'Content-Type': 'application/json' }
|
| 219 |
+
});
|
| 220 |
+
|
| 221 |
+
const data = await response.json();
|
| 222 |
+
if (data.status === 'Success' && data.redirect) {
|
| 223 |
+
window.location.href = data.redirect;
|
| 224 |
+
} else {
|
| 225 |
+
alert('Erreur lors de la déconnexion.');
|
| 226 |
+
}
|
| 227 |
+
};
|
| 228 |
+
|
| 229 |
+
// Assurez-vous que l'ID 'logout-button-sidebar' est utilisé sur votre bouton de déconnexion
|
| 230 |
+
document.getElementById('logout-button-sidebar').addEventListener('click', logoutHandler);
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
// 2.2. Récupération des Informations Utilisateur au chargement
|
| 234 |
+
const fetchUserInfo = async () => {
|
| 235 |
+
try {
|
| 236 |
+
const response = await fetch('/api/user/info', {
|
| 237 |
+
method: 'GET',
|
| 238 |
+
headers: { 'Content-Type': 'application/json' }
|
| 239 |
+
});
|
| 240 |
+
|
| 241 |
+
const data = await response.json();
|
| 242 |
+
|
| 243 |
+
if (data.status === 'Success') {
|
| 244 |
+
// Mettre à jour les éléments du DOM avec les données (email et plan)
|
| 245 |
+
document.getElementById('user-email').textContent = data.email || 'N/A';
|
| 246 |
+
document.getElementById('user-plan').textContent = data.plan ? data.plan.toUpperCase() : 'N/A';
|
| 247 |
+
|
| 248 |
+
// Optionnel : Afficher le user_id dans le dashboard
|
| 249 |
+
// document.getElementById('user-id-display').textContent = data.user_id;
|
| 250 |
+
|
| 251 |
+
} else if (response.status === 401 || data.message === 'Non autorisé') {
|
| 252 |
+
// Gérer la non-connexion (normalement géré par le décorateur Flask, mais utile ici)
|
| 253 |
+
window.location.href = '/connexion';
|
| 254 |
+
} else {
|
| 255 |
+
console.error('Erreur lors de la récupération des données utilisateur:', data.message);
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
} catch (error) {
|
| 259 |
+
console.error('Erreur réseau ou du serveur Flask:', error);
|
| 260 |
+
}
|
| 261 |
+
};
|
| 262 |
+
|
| 263 |
+
// Appeler la fonction au chargement de la page
|
| 264 |
+
window.addEventListener('load', fetchUserInfo);
|
| 265 |
+
|
| 266 |
+
</script>
|
| 267 |
+
</body>
|
| 268 |
+
</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,488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>Nexus - L'Avenir de la Technologie</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 |
+
/* ÉTAPE 2.1 : Définition des Variables de Thème (Adaptation Tailwind) */
|
| 12 |
+
/* Mode Sombre (Défaut) */
|
| 13 |
+
:root {
|
| 14 |
+
--bg-body: #0a0a0a; /* Sombre pour le body */
|
| 15 |
+
--bg-card: #1f2937; /* gray-800 */
|
| 16 |
+
--bg-section: #1f2937; /* gray-800/50 */
|
| 17 |
+
--bg-code: #1f2937; /* gray-800 */
|
| 18 |
+
--border-color: #4b5563; /* gray-600 */
|
| 19 |
+
--text-color: #ffffff;
|
| 20 |
+
--text-secondary: #d1d5db; /* gray-300 */
|
| 21 |
+
--text-muted: #9ca3af; /* gray-400 */
|
| 22 |
+
--text-blue: #3b82f6; /* blue-500 */
|
| 23 |
+
--shadow-color: rgba(0, 0, 0, 0.5); /* Ombre plus foncée */
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
/* Mode Clair */
|
| 27 |
+
html.light {
|
| 28 |
+
--bg-body: #ffffff;
|
| 29 |
+
--bg-card: #f3f4f6; /* gray-100 */
|
| 30 |
+
--bg-section: #e5e7eb; /* gray-200/50 */
|
| 31 |
+
--bg-code: #ffffff;
|
| 32 |
+
--border-color: #d1d5db; /* gray-300 */
|
| 33 |
+
--text-color: #1f2937; /* gray-800 */
|
| 34 |
+
--text-secondary: #4b5563; /* gray-600 */
|
| 35 |
+
--text-muted: #6b7280; /* gray-500 */
|
| 36 |
+
--text-blue: #2563eb; /* blue-600 */
|
| 37 |
+
--shadow-color: rgba(0, 0, 0, 0.1); /* Ombre plus claire */
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
/* Application des variables aux styles existants et aux nouveaux éléments */
|
| 41 |
+
/* ÉTAPE 2.2 : Appliquer les Variables (body et theme-switch) */
|
| 42 |
+
body {
|
| 43 |
+
font-family: 'Inter', sans-serif;
|
| 44 |
+
background-color: var(--bg-body);
|
| 45 |
+
color: var(--text-color);
|
| 46 |
+
min-height: 100vh;
|
| 47 |
+
transition: background-color 0.3s, color 0.3s; /* Transition pour un effet doux */
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.code-block {
|
| 51 |
+
border: 1px solid var(--border-color);
|
| 52 |
+
overflow-x: auto;
|
| 53 |
+
background-color: var(--bg-code);
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
/* Style du bouton (copié de l'exemple) */
|
| 57 |
+
.theme-switch {
|
| 58 |
+
background: none;
|
| 59 |
+
border: none;
|
| 60 |
+
cursor: pointer;
|
| 61 |
+
color: var(--text-color);
|
| 62 |
+
font-size: 24px;
|
| 63 |
+
transition: color 0.2s;
|
| 64 |
+
margin-left: 1rem; /* Espace le bouton du reste de la nav */
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
/* Adaptation Tailwind pour les autres éléments */
|
| 68 |
+
.header-border { border-color: var(--text-blue); }
|
| 69 |
+
.section-bg {
|
| 70 |
+
background-color: var(--bg-section);
|
| 71 |
+
border-color: var(--border-color);
|
| 72 |
+
box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -2px var(--shadow-color);
|
| 73 |
+
}
|
| 74 |
+
.card-bg { background-color: var(--bg-card); }
|
| 75 |
+
.text-blue-500-var { color: var(--text-blue); }
|
| 76 |
+
.text-gray-300-var { color: var(--text-secondary); }
|
| 77 |
+
.text-gray-400-var { color: var(--text-muted); }
|
| 78 |
+
|
| 79 |
+
/* Ajustements spécifiques pour les éléments non couverts par une classe personnalisée */
|
| 80 |
+
header { border-bottom: 1px solid var(--text-blue); }
|
| 81 |
+
footer { border-top: 1px solid var(--border-color); }
|
| 82 |
+
.tab-button { border-bottom-color: var(--border-color); }
|
| 83 |
+
.tab-button.border-blue-500 { border-bottom-color: var(--text-blue) !important; color: var(--text-blue) !important; background-color: var(--bg-code) !important; }
|
| 84 |
+
.tab-button.hover\:text-white:hover { color: var(--text-color) !important; }
|
| 85 |
+
.tab-button.hover\:bg-gray-800:hover { background-color: var(--bg-card) !important; }
|
| 86 |
+
|
| 87 |
+
.bg-blue-900\/40 { background-color: rgba(29, 78, 216, 0.4); } /* Couleur fixe car c'est un accent */
|
| 88 |
+
</style>
|
| 89 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
|
| 90 |
+
</head>
|
| 91 |
+
<body>
|
| 92 |
+
|
| 93 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 94 |
+
|
| 95 |
+
<header class="flex flex-col sm:flex-row justify-between items-center py-4 header-border mb-8">
|
| 96 |
+
<h1 class="text-4xl font-extrabold text-blue-500-var tracking-wider mb-4 sm:mb-0">
|
| 97 |
+
NEXUS
|
| 98 |
+
</h1>
|
| 99 |
+
<nav class="flex items-center space-x-4">
|
| 100 |
+
{% if user_id %}
|
| 101 |
+
<span class="text-sm text-gray-400-var hidden md:block">Connecté : <strong class="text-color">{{ user_id[:8] }}...</strong></span>
|
| 102 |
+
{% else %}
|
| 103 |
+
<span class="text-sm text-gray-400-var hidden md:block">Non connecté</span>
|
| 104 |
+
{% endif %}
|
| 105 |
+
|
| 106 |
+
<a href="/documentation" class="px-4 py-2 text-color hover:text-blue-500-var transition duration-200 font-medium">
|
| 107 |
+
Documentation
|
| 108 |
+
</a>
|
| 109 |
+
<a href="/tarifs" class="px-4 py-2 text-color hover:text-blue-500-var transition duration-200 font-medium">
|
| 110 |
+
Tarifs
|
| 111 |
+
</a>
|
| 112 |
+
<a href="/a-propos" class="px-4 py-2 text-color hover:text-blue-500-var transition duration-200 font-medium">
|
| 113 |
+
À Propos
|
| 114 |
+
</a>
|
| 115 |
+
<a href="/support" class="px-4 py-2 text-color hover:text-blue-500-var transition duration-200 font-medium">
|
| 116 |
+
Support
|
| 117 |
+
</a>
|
| 118 |
+
|
| 119 |
+
{% if is_logged_in %}
|
| 120 |
+
<a href="/profile" class="px-4 py-2 text-color hover:text-blue-500-var transition duration-200 font-medium hidden sm:block">
|
| 121 |
+
Profil
|
| 122 |
+
</a>
|
| 123 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 124 |
+
Dashboard
|
| 125 |
+
</a>
|
| 126 |
+
<button id="logout-button" class="px-4 py-2 bg-red-600 hover:bg-red-700 font-medium transition duration-200 hidden sm:block">
|
| 127 |
+
Déconnexion
|
| 128 |
+
</button>
|
| 129 |
+
{% else %}
|
| 130 |
+
<a href="/connexion" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 131 |
+
Connexion
|
| 132 |
+
</a>
|
| 133 |
+
<a href="/inscription" class="px-4 py-2 border-2 border-blue-600 text-blue-600 hover:bg-blue-600 hover:text-white font-medium transition duration-200 hidden sm:block">
|
| 134 |
+
Inscription
|
| 135 |
+
</a>
|
| 136 |
+
{% endif %}
|
| 137 |
+
|
| 138 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 139 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 140 |
+
</button>
|
| 141 |
+
</nav>
|
| 142 |
+
</header>
|
| 143 |
+
|
| 144 |
+
<main class="space-y-16">
|
| 145 |
+
|
| 146 |
+
<section class="text-center p-8 section-bg shadow-lg border border-gray-700">
|
| 147 |
+
<h2 class="text-5xl font-extrabold text-color mb-4 leading-tight">
|
| 148 |
+
Nexus : Plateforme d'Authentification Unifiée
|
| 149 |
+
</h2>
|
| 150 |
+
<p class="text-xl text-gray-300-var max-w-4xl mx-auto">
|
| 151 |
+
Construisez, déployez et connectez vos applications en toute sécurité. <strong class="text-blue-400">Pas de configuration requise, juste une API et une URL.</strong>
|
| 152 |
+
</p>
|
| 153 |
+
{% if not is_logged_in %}
|
| 154 |
+
<div class="mt-8 flex justify-center space-x-4">
|
| 155 |
+
<a href="/inscription" class="px-6 py-3 bg-blue-600 text-white text-lg font-bold shadow-md hover:bg-blue-700 transition duration-300">
|
| 156 |
+
Commencer Gratuitement
|
| 157 |
+
</a>
|
| 158 |
+
<a href="/documentation" class="px-6 py-3 border-2 border-blue-600 text-blue-600 hover:bg-blue-600 hover:text-white text-lg font-bold shadow-md transition duration-300">
|
| 159 |
+
Lire la Documentation
|
| 160 |
+
</a>
|
| 161 |
+
</div>
|
| 162 |
+
{% endif %}
|
| 163 |
+
</section>
|
| 164 |
+
|
| 165 |
+
<section>
|
| 166 |
+
<h2 class="text-4xl font-extrabold text-color mb-8 text-center">
|
| 167 |
+
Pourquoi Choisir Nexus ?
|
| 168 |
+
</h2>
|
| 169 |
+
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
| 170 |
+
<div class="card-bg p-6 shadow-xl border-t-4 border-teal-500">
|
| 171 |
+
<h3 class="text-2xl font-semibold text-teal-400 mb-3">Sécurité Zéro Confiance</h3>
|
| 172 |
+
<p class="text-gray-300-var text-sm">Chiffrement de bout en bout et gestion des tokens JWT pour une protection maximale des données utilisateurs.</p>
|
| 173 |
+
</div>
|
| 174 |
+
<div class="card-bg p-6 shadow-xl border-t-4 border-yellow-500">
|
| 175 |
+
<h3 class="text-2xl font-semibold text-yellow-400 mb-3">Scalabilité Robuste</h3>
|
| 176 |
+
<p class="text-gray-300-var text-sm">Architecture conçue pour gérer des millions de comptes et des pics de trafic sans dégradation de performance.</p>
|
| 177 |
+
</div>
|
| 178 |
+
<div class="card-bg p-6 shadow-xl border-t-4 border-purple-500">
|
| 179 |
+
<h3 class="text-2xl font-semibold text-purple-400 mb-3">Logs et Monitoring</h3>
|
| 180 |
+
<p class="text-gray-300-var text-sm">Accès à des logs API détaillés pour suivre les tentatives de connexion et les erreurs en temps réel.</p>
|
| 181 |
+
</div>
|
| 182 |
+
<div class="card-bg p-6 shadow-xl border-t-4 border-blue-500">
|
| 183 |
+
<h3 class="text-2xl font-semibold text-blue-400 mb-3">Intégration Universelle</h3>
|
| 184 |
+
<p class="text-gray-300-var text-sm">API REST simple utilisable dans n'importe quel langage ou framework (Python, Node.js, PHP, Go, etc.).</p>
|
| 185 |
+
</div>
|
| 186 |
+
</div>
|
| 187 |
+
</section>
|
| 188 |
+
|
| 189 |
+
<section>
|
| 190 |
+
<h2 class="text-4xl font-extrabold text-color mb-6 text-center">
|
| 191 |
+
Intégration Instantanée
|
| 192 |
+
</h2>
|
| 193 |
+
<p class="text-lg text-gray-400-var max-w-3xl mx-auto text-center mb-8">
|
| 194 |
+
Authentifiez vos utilisateurs en quelques lignes de code seulement.
|
| 195 |
+
</p>
|
| 196 |
+
|
| 197 |
+
<div class="max-w-4xl mx-auto">
|
| 198 |
+
<div id="language-tabs" class="flex flex-wrap sm:flex-nowrap mb-0 border-b border-gray-700">
|
| 199 |
+
<button data-lang="python" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-blue-500 text-blue-500 bg-gray-800 hover:bg-gray-700 flex-grow sm:flex-grow-0 transition duration-200">
|
| 200 |
+
Python
|
| 201 |
+
</button>
|
| 202 |
+
<button data-lang="javascript" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-transparent text-gray-400 hover:text-white hover:bg-gray-800 flex-grow sm:flex-grow-0 transition duration-200">
|
| 203 |
+
JavaScript
|
| 204 |
+
</button>
|
| 205 |
+
<button data-lang="php" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-transparent text-gray-400 hover:text-white hover:bg-gray-800 flex-grow sm:flex-grow-0 transition duration-200">
|
| 206 |
+
PHP
|
| 207 |
+
</button>
|
| 208 |
+
<button data-lang="bash" class="tab-button px-4 py-3 text-lg font-semibold border-b-2 border-transparent text-gray-400 hover:text-white hover:bg-gray-800 flex-grow sm:flex-grow-0 transition duration-200">
|
| 209 |
+
cURL (Bash)
|
| 210 |
+
</button>
|
| 211 |
+
</div>
|
| 212 |
+
|
| 213 |
+
<div id="code-content" class="code-block p-4 pt-6 text-sm">
|
| 214 |
+
|
| 215 |
+
<pre><code id="code-python" class="language-python tab-code">import requests
|
| 216 |
+
import json
|
| 217 |
+
|
| 218 |
+
# URL de l'API Nexus pour l'inscription
|
| 219 |
+
url = "https://ernestmindres-nexus.hf.space/api/register"
|
| 220 |
+
headers = {"Content-Type": "application/json"}
|
| 221 |
+
payload = {"email": "utilisateur@example.com", "password": "MonMotDePasse"}
|
| 222 |
+
|
| 223 |
+
# Envoi de la requête POST
|
| 224 |
+
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
| 225 |
+
print(response.json())</code></pre>
|
| 226 |
+
|
| 227 |
+
<pre class="hidden"><code id="code-javascript" class="language-javascript tab-code">const registerUser = async () => {
|
| 228 |
+
// URL de l'API Nexus pour l'inscription
|
| 229 |
+
const url = 'https://ernestmindres-nexus.hf.space/api/register';
|
| 230 |
+
|
| 231 |
+
const response = await fetch(url, {
|
| 232 |
+
method: 'POST',
|
| 233 |
+
headers: { 'Content-Type': 'application/json' },
|
| 234 |
+
body: JSON.stringify({
|
| 235 |
+
email: 'utilisateur@example.com',
|
| 236 |
+
password: 'MonMotDePasse'
|
| 237 |
+
})
|
| 238 |
+
});
|
| 239 |
+
|
| 240 |
+
const data = await response.json();
|
| 241 |
+
console.log(data);
|
| 242 |
+
};
|
| 243 |
+
|
| 244 |
+
registerUser();</code></pre>
|
| 245 |
+
|
| 246 |
+
<pre class="hidden"><code id="code-php" class="language-php tab-code"><?php
|
| 247 |
+
// URL de l'API Nexus pour l'inscription
|
| 248 |
+
$url = "https://ernestmindres-nexus.hf.space/api/register";
|
| 249 |
+
$data = array("email" => "utilisateur@example.com", "password" => "MonMotDePasse");
|
| 250 |
+
|
| 251 |
+
$curl = curl_init();
|
| 252 |
+
|
| 253 |
+
curl_setopt_array($curl, array(
|
| 254 |
+
CURLOPT_URL => $url,
|
| 255 |
+
CURLOPT_RETURNTRANSFER => true,
|
| 256 |
+
CURLOPT_POST => true,
|
| 257 |
+
CURLOPT_HTTPHEADER => array('Content-Type: application/json'),
|
| 258 |
+
CURLOPT_POSTFIELDS => json_encode($data)
|
| 259 |
+
));
|
| 260 |
+
|
| 261 |
+
$response = curl_exec($curl);
|
| 262 |
+
curl_close($curl);
|
| 263 |
+
print_r(json_decode($response, true));
|
| 264 |
+
?></code></pre>
|
| 265 |
+
|
| 266 |
+
<pre class="hidden"><code id="code-bash" class="language-bash tab-code"># URL de l'API Nexus pour l'inscription
|
| 267 |
+
curl -X POST \
|
| 268 |
+
-H "Content-Type: application/json" \
|
| 269 |
+
-d '{"email": "utilisateur@example.com", "password": "MonMotDePasse"}' \
|
| 270 |
+
"https://ernestmindres-nexus.hf.space/api/register"</code></pre>
|
| 271 |
+
</div>
|
| 272 |
+
</div>
|
| 273 |
+
</section>
|
| 274 |
+
|
| 275 |
+
<section class="max-w-4xl mx-auto bg-blue-900/40 p-8 shadow-xl border border-blue-600">
|
| 276 |
+
<div class="flex flex-col md:flex-row items-center space-y-4 md:space-y-0 md:space-x-8">
|
| 277 |
+
<svg class="w-12 h-12 text-blue-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
|
| 278 |
+
<div>
|
| 279 |
+
<h3 class="text-3xl font-bold text-color mb-2">Conçu pour l'Évolutivité Illimitée</h3>
|
| 280 |
+
<p class="text-blue-200">
|
| 281 |
+
Notre architecture est élastique. De 10 à 10 millions d'utilisateurs, Nexus s'adapte automatiquement. Atteignez la croissance sans jamais vous soucier des limites techniques. Découvrez notre <a href="/tarifs" class="text-yellow-400 underline font-semibold">Plan Entreprise Illimité</a>.
|
| 282 |
+
</p>
|
| 283 |
+
</div>
|
| 284 |
+
</div>
|
| 285 |
+
</section>
|
| 286 |
+
|
| 287 |
+
</main>
|
| 288 |
+
|
| 289 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 290 |
+
© 2024 Nexus. Tous droits réservés. | Politique de Confidentialité
|
| 291 |
+
</footer>
|
| 292 |
+
</div>
|
| 293 |
+
|
| 294 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
| 295 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>
|
| 296 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
|
| 297 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/php.min.js"></script>
|
| 298 |
+
|
| 299 |
+
<script>
|
| 300 |
+
// ÉTAPE 3.1 : Intégrer la Logique JavaScript du Mode Sombre/Clair
|
| 301 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 302 |
+
const htmlElement = document.documentElement;
|
| 303 |
+
// Vérifiez si le bouton et son contenu existent avant d'essayer de le manipuler
|
| 304 |
+
const iconElement = themeToggle ? themeToggle.querySelector('.material-symbols-rounded') : null;
|
| 305 |
+
|
| 306 |
+
// Charger le thème depuis le localStorage
|
| 307 |
+
const savedTheme = localStorage.getItem('theme');
|
| 308 |
+
|
| 309 |
+
if (iconElement) {
|
| 310 |
+
if (savedTheme === 'light') {
|
| 311 |
+
htmlElement.classList.add('light');
|
| 312 |
+
iconElement.textContent = 'dark_mode'; // Afficher l'icône de lune
|
| 313 |
+
} else {
|
| 314 |
+
// Par défaut ou 'dark'
|
| 315 |
+
htmlElement.classList.remove('light');
|
| 316 |
+
iconElement.textContent = 'light_mode'; // Afficher l'icône de soleil
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
if (themeToggle) {
|
| 321 |
+
themeToggle.addEventListener('click', () => {
|
| 322 |
+
if (htmlElement.classList.contains('light')) {
|
| 323 |
+
// Passer au mode sombre
|
| 324 |
+
htmlElement.classList.remove('light');
|
| 325 |
+
localStorage.setItem('theme', 'dark');
|
| 326 |
+
if (iconElement) iconElement.textContent = 'light_mode'; // Afficher le soleil
|
| 327 |
+
} else {
|
| 328 |
+
// Passer au mode clair
|
| 329 |
+
htmlElement.classList.add('light');
|
| 330 |
+
localStorage.setItem('theme', 'light');
|
| 331 |
+
if (iconElement) iconElement.textContent = 'dark_mode'; // Afficher la lune
|
| 332 |
+
}
|
| 333 |
+
});
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
// Logique de changement d'onglet (responsive)
|
| 337 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 338 |
+
const tabsContainer = document.getElementById('language-tabs');
|
| 339 |
+
const codeBlocks = document.querySelectorAll('.tab-code');
|
| 340 |
+
const tabButtons = document.querySelectorAll('.tab-button');
|
| 341 |
+
|
| 342 |
+
function showCode(lang) {
|
| 343 |
+
// Masquer tous les blocs de code
|
| 344 |
+
codeBlocks.forEach(block => block.parentElement.classList.add('hidden'));
|
| 345 |
+
|
| 346 |
+
// Mettre à jour l'état des boutons
|
| 347 |
+
tabButtons.forEach(button => {
|
| 348 |
+
if (button.dataset.lang === lang) {
|
| 349 |
+
// Utilisation des classes CSS pour gérer le style actif
|
| 350 |
+
button.classList.add('border-blue-500', 'text-blue-500-var');
|
| 351 |
+
button.classList.remove('border-transparent', 'text-gray-400-var', 'hover:text-white', 'hover:bg-gray-800');
|
| 352 |
+
} else {
|
| 353 |
+
button.classList.remove('border-blue-500', 'text-blue-500-var');
|
| 354 |
+
button.classList.add('border-transparent', 'text-gray-400-var', 'hover:text-white', 'hover:bg-gray-800');
|
| 355 |
+
}
|
| 356 |
+
});
|
| 357 |
+
|
| 358 |
+
// Afficher le bloc de code sélectionné
|
| 359 |
+
const selectedCodeBlock = document.getElementById(`code-${lang}`);
|
| 360 |
+
if (selectedCodeBlock) {
|
| 361 |
+
selectedCodeBlock.parentElement.classList.remove('hidden');
|
| 362 |
+
// Ré-initialiser la coloration après changement (au cas où)
|
| 363 |
+
hljs.highlightElement(selectedCodeBlock);
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
if (tabsContainer) {
|
| 368 |
+
tabsContainer.addEventListener('click', (event) => {
|
| 369 |
+
if (event.target.classList.contains('tab-button')) {
|
| 370 |
+
const lang = event.target.dataset.lang;
|
| 371 |
+
showCode(lang);
|
| 372 |
+
}
|
| 373 |
+
});
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
// Initialisation de la coloration syntaxique
|
| 377 |
+
hljs.highlightAll();
|
| 378 |
+
|
| 379 |
+
// Afficher Python par défaut au chargement
|
| 380 |
+
showCode('python');
|
| 381 |
+
});
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
// Logique existante de déconnexion et de message
|
| 385 |
+
function showMessageBox(message, isError = true) {
|
| 386 |
+
const container = document.body;
|
| 387 |
+
let messageBox = document.getElementById('custom-message-box');
|
| 388 |
+
if (!messageBox) {
|
| 389 |
+
messageBox = document.createElement('div');
|
| 390 |
+
messageBox.id = 'custom-message-box';
|
| 391 |
+
messageBox.className = 'fixed top-4 right-4 p-4 shadow-xl text-white font-medium z-50 transition-opacity duration-300';
|
| 392 |
+
container.appendChild(messageBox);
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
messageBox.textContent = message;
|
| 396 |
+
messageBox.className = messageBox.className.replace(/bg-red-\d+\/50|bg-green-\d+\/50|text-red-\d+|text-green-\d+/g, '').trim();
|
| 397 |
+
|
| 398 |
+
if (isError) {
|
| 399 |
+
messageBox.classList.add('bg-red-800/80', 'text-red-100');
|
| 400 |
+
} else {
|
| 401 |
+
messageBox.classList.add('bg-green-800/80', 'text-green-100');
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
messageBox.style.opacity = '1';
|
| 405 |
+
|
| 406 |
+
setTimeout(() => {
|
| 407 |
+
messageBox.style.opacity = '0';
|
| 408 |
+
}, 3000); // Masquer après 3 secondes
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
// Ajoutez l'écouteur d'événement seulement si l'utilisateur est connecté
|
| 412 |
+
{% if is_logged_in %}
|
| 413 |
+
document.getElementById('logout-button').addEventListener('click', async () => {
|
| 414 |
+
const response = await fetch('/logout', {
|
| 415 |
+
method: 'POST',
|
| 416 |
+
headers: { 'Content-Type': 'application/json' }
|
| 417 |
+
});
|
| 418 |
+
|
| 419 |
+
const data = await response.json();
|
| 420 |
+
if (data.status === 'Success' && data.redirect) {
|
| 421 |
+
// Redirection vers la page de connexion après déconnexion réussie
|
| 422 |
+
showMessageBox("Déconnexion réussie.", false);
|
| 423 |
+
setTimeout(() => {
|
| 424 |
+
window.location.href = data.redirect;
|
| 425 |
+
}, 1000);
|
| 426 |
+
} else {
|
| 427 |
+
console.error("Erreur lors de la déconnexion.", data.message);
|
| 428 |
+
showMessageBox(data.message || "Erreur de déconnexion. Veuillez réessayer.", true);
|
| 429 |
+
}
|
| 430 |
+
});
|
| 431 |
+
{% endif %}
|
| 432 |
+
</script>
|
| 433 |
+
|
| 434 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900">
|
| 435 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 436 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 437 |
+
|
| 438 |
+
<div class="col-span-2 lg:col-span-1">
|
| 439 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500-var tracking-wider">NEXUS</a>
|
| 440 |
+
<p class="mt-3 text-gray-400-var">
|
| 441 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 442 |
+
</p>
|
| 443 |
+
<div class="mt-4 flex space-x-4">
|
| 444 |
+
<a href="#" class="text-gray-400-var hover:text-blue-500-var transition duration-200">
|
| 445 |
+
<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>
|
| 446 |
+
</a>
|
| 447 |
+
</div>
|
| 448 |
+
</div>
|
| 449 |
+
|
| 450 |
+
<div>
|
| 451 |
+
<h3 class="text-lg font-semibold text-color mb-4">Plateforme</h3>
|
| 452 |
+
<ul class="space-y-3 text-gray-400-var">
|
| 453 |
+
<li><a href="/tarifs" class="hover:text-blue-500-var transition duration-200">Tarifs</a></li>
|
| 454 |
+
<li><a href="/documentation" class="hover:text-blue-500-var transition duration-200">Documentation</a></li>
|
| 455 |
+
<li><a href="/connexion" class="hover:text-blue-500-var transition duration-200">Connexion</a></li>
|
| 456 |
+
<li><a href="/support" class="hover:text-blue-500-var transition duration-200">Support</a></li>
|
| 457 |
+
</ul>
|
| 458 |
+
</div>
|
| 459 |
+
|
| 460 |
+
<div>
|
| 461 |
+
<h3 class="text-lg font-semibold text-color mb-4">Légal</h3>
|
| 462 |
+
<ul class="space-y-3 text-gray-400-var">
|
| 463 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500-var transition duration-200">Politique de Confidentialité</a></li>
|
| 464 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500-var transition duration-200">Mentions Légales</a></li>
|
| 465 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500-var transition duration-200">Conditions d'Utilisation</a></li>
|
| 466 |
+
<li><a href="/a-propos" class="hover:text-blue-500-var transition duration-200">À Propos</a></li>
|
| 467 |
+
</ul>
|
| 468 |
+
</div>
|
| 469 |
+
|
| 470 |
+
<div class="col-span-2 md:col-span-1">
|
| 471 |
+
<h3 class="text-lg font-semibold text-color mb-4">Ressources</h3>
|
| 472 |
+
<ul class="space-y-3 text-gray-400-var">
|
| 473 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500-var transition duration-200">Contact Email</a></li>
|
| 474 |
+
<li><a href="/dashboard" class="hover:text-blue-500-var transition duration-200">Espace Client</a></li>
|
| 475 |
+
<li><a href="/api-logs" class="hover:text-blue-500-var transition duration-200">Statut API</a></li>
|
| 476 |
+
</ul>
|
| 477 |
+
</div>
|
| 478 |
+
|
| 479 |
+
</div>
|
| 480 |
+
|
| 481 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm">
|
| 482 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 483 |
+
</div>
|
| 484 |
+
</div>
|
| 485 |
+
</footer>
|
| 486 |
+
|
| 487 |
+
</body>
|
| 488 |
+
</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/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,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>Mon Profil - Nexus Pro</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 |
+
/* Forcer le thème sombre/clair de Tailwind via la classe 'dark' sur <html> */
|
| 13 |
+
.dark .bg-gray-900 { background-color: #121212; } /* Noir très foncé */
|
| 14 |
+
.dark .text-white { color: #E3E3E3; }
|
| 15 |
+
.light .bg-gray-900 { background-color: #F8F8F8; }
|
| 16 |
+
.light .text-white { color: #333333; }
|
| 17 |
+
|
| 18 |
+
/* Ajustements de couleur pour le mode clair */
|
| 19 |
+
.light .bg-gray-800 { background-color: #FFFFFF; border: 1px solid #E5E7EB; }
|
| 20 |
+
.light .text-gray-400 { color: #6B7280; }
|
| 21 |
+
.light .bg-gray-700 { background-color: #F3F4F6; }
|
| 22 |
+
.light .text-blue-500 { color: #1D4ED8; }
|
| 23 |
+
.light .text-yellow-500 { color: #D97706; }
|
| 24 |
+
.light .border-gray-700 { border-color: #D1D5DB; }
|
| 25 |
+
.light #logout-button { background-color: #DC2626; }
|
| 26 |
+
.light #logout-button:hover { background-color: #B91C1C; }
|
| 27 |
+
|
| 28 |
+
.light #passwordUpdateForm .bg-gray-700 { background-color: #F3F4F6; color: #1F2937; }
|
| 29 |
+
.light #passwordUpdateForm input:focus { border-color: #D97706; }
|
| 30 |
+
|
| 31 |
+
</style>
|
| 32 |
+
</head>
|
| 33 |
+
<body class="bg-gray-900 text-white min-h-screen transition-colors duration-300">
|
| 34 |
+
|
| 35 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8">
|
| 36 |
+
|
| 37 |
+
<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 transition-colors duration-300">
|
| 38 |
+
<h1 class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 39 |
+
Mon Profil
|
| 40 |
+
</h1>
|
| 41 |
+
<nav class="flex items-center space-x-4">
|
| 42 |
+
<button id="theme-toggle" class="theme-switch p-2 rounded-full hover:bg-gray-700 transition duration-200" aria-label="Basculer le thème">
|
| 43 |
+
<span class="material-symbols-rounded text-white dark:text-white light:text-gray-800 text-2xl">
|
| 44 |
+
light_mode
|
| 45 |
+
</span>
|
| 46 |
+
</button>
|
| 47 |
+
<a href="/dashboard" class="px-4 py-2 text-white hover:text-blue-300 light:text-gray-800 light:hover:text-blue-500 transition duration-200 font-medium">
|
| 48 |
+
Dashboard
|
| 49 |
+
</a>
|
| 50 |
+
<span class="text-sm text-gray-400 hidden md:block">
|
| 51 |
+
ID Utilisateur : <strong class="text-white light:text-gray-800">{{ user_id }}</strong>
|
| 52 |
+
</span>
|
| 53 |
+
<button id="logout-button" class="px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg transition duration-200 font-medium shadow-md">
|
| 54 |
+
Déconnexion
|
| 55 |
+
</button>
|
| 56 |
+
</nav>
|
| 57 |
+
</header>
|
| 58 |
+
|
| 59 |
+
<main class="space-y-10 max-w-4xl mx-auto">
|
| 60 |
+
|
| 61 |
+
<div class="p-8 bg-gray-800 rounded-xl shadow-2xl border-l-4 border-blue-500 transition-colors duration-300">
|
| 62 |
+
<h2 class="text-3xl font-bold text-blue-500 mb-6">Détails du Compte</h2>
|
| 63 |
+
|
| 64 |
+
<div class="space-y-4">
|
| 65 |
+
<div>
|
| 66 |
+
<p class="text-sm font-medium text-gray-400">ID Utilisateur Nexus</p>
|
| 67 |
+
<p class="text-lg font-mono text-white p-3 bg-gray-700 rounded-lg select-all transition-colors duration-300">{{ user_id }}</p>
|
| 68 |
+
</div>
|
| 69 |
+
<div>
|
| 70 |
+
<p class="text-sm font-medium text-gray-400">Adresse E-mail (Placeholder)</p>
|
| 71 |
+
<p class="text-lg text-white p-3 bg-gray-700 rounded-lg transition-colors duration-300">utilisateur.exemple@nexus.pro</p>
|
| 72 |
+
</div>
|
| 73 |
+
<p class="text-sm text-gray-500 mt-4">
|
| 74 |
+
*L'e-mail réel devrait être chargé via une requête GET à l'API Nexus (`/api/user/{{ user_id }}`).
|
| 75 |
+
</p>
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
|
| 79 |
+
<div class="p-8 bg-gray-800 rounded-xl shadow-2xl border-l-4 border-yellow-500 transition-colors duration-300">
|
| 80 |
+
<h2 class="text-3xl font-bold text-yellow-500 mb-6">Sécurité et Mot de Passe</h2>
|
| 81 |
+
|
| 82 |
+
<form id="passwordUpdateForm" class="space-y-6">
|
| 83 |
+
<div>
|
| 84 |
+
<label for="new_password" class="block text-sm font-medium text-gray-300 light:text-gray-600 mb-1">Nouveau Mot de passe</label>
|
| 85 |
+
<input type="password" id="new_password" name="new_password" required
|
| 86 |
+
class="w-full px-4 py-3 bg-gray-700 text-white border-2 border-gray-700 rounded-lg focus:border-yellow-500 transition duration-200 light:border-gray-300 light:bg-white light:text-gray-900"
|
| 87 |
+
placeholder="Nouveau mot de passe">
|
| 88 |
+
</div>
|
| 89 |
+
<div>
|
| 90 |
+
<label for="confirm_password" class="block text-sm font-medium text-gray-300 light:text-gray-600 mb-1">Confirmer le Mot de passe</label>
|
| 91 |
+
<input type="password" id="confirm_password" name="confirm_password" required
|
| 92 |
+
class="w-full px-4 py-3 bg-gray-700 text-white border-2 border-gray-700 rounded-lg focus:border-yellow-500 transition duration-200 light:border-gray-300 light:bg-white light:text-gray-900"
|
| 93 |
+
placeholder="Confirmer le mot de passe">
|
| 94 |
+
</div>
|
| 95 |
+
|
| 96 |
+
<div id="messageBoxProfile" class="text-sm p-3 rounded-lg hidden" role="alert"></div>
|
| 97 |
+
|
| 98 |
+
<button type="submit"
|
| 99 |
+
class="w-full py-3 bg-yellow-600 hover:bg-yellow-700 text-white font-semibold rounded-lg transition duration-300 shadow-lg">
|
| 100 |
+
Mettre à jour le Mot de Passe
|
| 101 |
+
</button>
|
| 102 |
+
</form>
|
| 103 |
+
</div>
|
| 104 |
+
</main>
|
| 105 |
+
|
| 106 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm transition-colors duration-300">
|
| 107 |
+
© 2024 Nexus. Tous droits réservés. | Espace Sécurisé
|
| 108 |
+
</footer>
|
| 109 |
+
</div>
|
| 110 |
+
|
| 111 |
+
<script>
|
| 112 |
+
// ... (Existing Sidebar and Theme Toggle Logic) ...
|
| 113 |
+
|
| 114 |
+
const profileForm = document.getElementById('profile-form');
|
| 115 |
+
const messageBox = document.getElementById('profile-message');
|
| 116 |
+
const emailInput = document.getElementById('email-input');
|
| 117 |
+
const currentPlanDisplay = document.getElementById('current-plan');
|
| 118 |
+
const updateButton = document.getElementById('update-button');
|
| 119 |
+
|
| 120 |
+
// 1.3. Logique de Déconnexion
|
| 121 |
+
const logoutHandler = async (e) => {
|
| 122 |
+
e.preventDefault();
|
| 123 |
+
// Appel à la route de déconnexion Flask
|
| 124 |
+
const response = await fetch('/logout', { method: 'POST' });
|
| 125 |
+
const data = await response.json();
|
| 126 |
+
if (data.status === 'Success' && data.redirect) {
|
| 127 |
+
window.location.href = data.redirect;
|
| 128 |
+
} else {
|
| 129 |
+
alert('Erreur lors de la déconnexion.');
|
| 130 |
+
}
|
| 131 |
+
};
|
| 132 |
+
document.getElementById('logout-button-sidebar').addEventListener('click', logoutHandler);
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
// 2.2. Récupération des Informations Utilisateur (Email et Plan)
|
| 136 |
+
const fetchUserInfo = async () => {
|
| 137 |
+
try {
|
| 138 |
+
const response = await fetch('/api/user/info', { method: 'GET' });
|
| 139 |
+
const data = await response.json();
|
| 140 |
+
|
| 141 |
+
if (data.status === 'Success') {
|
| 142 |
+
emailInput.value = data.email || 'N/A';
|
| 143 |
+
currentPlanDisplay.textContent = data.plan ? data.plan.toUpperCase() : 'N/A';
|
| 144 |
+
emailInput.disabled = true; // L'email ne doit pas être modifiable ici
|
| 145 |
+
} else {
|
| 146 |
+
console.error('Erreur lors de la récupération des données utilisateur:', data.message);
|
| 147 |
+
messageBox.textContent = 'Erreur: Impossible de charger les données du profil.';
|
| 148 |
+
messageBox.classList.remove('hidden');
|
| 149 |
+
}
|
| 150 |
+
} catch (error) {
|
| 151 |
+
console.error('Erreur réseau:', error);
|
| 152 |
+
}
|
| 153 |
+
};
|
| 154 |
+
|
| 155 |
+
// 3.3. Logique de Mise à Jour du Profil (Exemple : Plan)
|
| 156 |
+
profileForm.addEventListener('submit', async (e) => {
|
| 157 |
+
e.preventDefault();
|
| 158 |
+
messageBox.classList.add('hidden');
|
| 159 |
+
updateButton.disabled = true;
|
| 160 |
+
|
| 161 |
+
// Récupérer la valeur du plan sélectionné (adapter selon la structure de votre formulaire)
|
| 162 |
+
// Ici, on suppose un champ caché ou une déduction si le plan est le seul à être mis à jour.
|
| 163 |
+
// Pour l'exemple, nous allons simuler le passage au plan 'premium' comme dans votre test cURL
|
| 164 |
+
const newPlan = 'premium';
|
| 165 |
+
|
| 166 |
+
try {
|
| 167 |
+
const response = await fetch('/api/user/update-info', {
|
| 168 |
+
method: 'POST',
|
| 169 |
+
headers: { 'Content-Type': 'application/json' },
|
| 170 |
+
body: JSON.stringify({ plan: newPlan })
|
| 171 |
+
});
|
| 172 |
+
|
| 173 |
+
const data = await response.json();
|
| 174 |
+
|
| 175 |
+
if (data.status === 'Success') {
|
| 176 |
+
messageBox.classList.remove('bg-red-900/50', 'text-red-300');
|
| 177 |
+
messageBox.classList.add('bg-green-900/50', 'text-green-300');
|
| 178 |
+
messageBox.textContent = data.message || "Profil mis à jour avec succès.";
|
| 179 |
+
|
| 180 |
+
// Mettre à jour l'affichage du plan (et recharger les données pour s'assurer)
|
| 181 |
+
fetchUserInfo();
|
| 182 |
+
} else {
|
| 183 |
+
messageBox.classList.remove('bg-green-900/50', 'text-green-300');
|
| 184 |
+
messageBox.classList.add('bg-red-900/50', 'text-red-300');
|
| 185 |
+
messageBox.textContent = data.message || "Erreur lors de la mise à jour du profil.";
|
| 186 |
+
}
|
| 187 |
+
messageBox.classList.remove('hidden');
|
| 188 |
+
|
| 189 |
+
} catch (error) {
|
| 190 |
+
messageBox.classList.remove('bg-green-900/50', 'text-green-300');
|
| 191 |
+
messageBox.classList.add('bg-red-900/50', 'text-red-300');
|
| 192 |
+
messageBox.textContent = "Erreur réseau: Impossible de communiquer avec le serveur.";
|
| 193 |
+
messageBox.classList.remove('hidden');
|
| 194 |
+
} finally {
|
| 195 |
+
updateButton.disabled = false;
|
| 196 |
+
}
|
| 197 |
+
});
|
| 198 |
+
|
| 199 |
+
// Appeler au chargement
|
| 200 |
+
window.addEventListener('load', fetchUserInfo);
|
| 201 |
+
|
| 202 |
+
</script>
|
| 203 |
+
|
| 204 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900 transition-colors duration-300">
|
| 205 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 206 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 207 |
+
|
| 208 |
+
<div class="col-span-2 lg:col-span-1">
|
| 209 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 210 |
+
<p class="mt-3 text-gray-400">
|
| 211 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 212 |
+
</p>
|
| 213 |
+
<div class="mt-4 flex space-x-4">
|
| 214 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 215 |
+
<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>
|
| 216 |
+
</a>
|
| 217 |
+
</div>
|
| 218 |
+
</div>
|
| 219 |
+
|
| 220 |
+
<div>
|
| 221 |
+
<h3 class="text-lg font-semibold text-white light:text-gray-900 mb-4">Plateforme</h3>
|
| 222 |
+
<ul class="space-y-3 text-gray-400">
|
| 223 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 224 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 225 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 226 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 227 |
+
</ul>
|
| 228 |
+
</div>
|
| 229 |
+
|
| 230 |
+
<div>
|
| 231 |
+
<h3 class="text-lg font-semibold text-white light:text-gray-900 mb-4">Légal</h3>
|
| 232 |
+
<ul class="space-y-3 text-gray-400">
|
| 233 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 234 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 235 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 236 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 237 |
+
</ul>
|
| 238 |
+
</div>
|
| 239 |
+
|
| 240 |
+
<div class="col-span-2 md:col-span-1">
|
| 241 |
+
<h3 class="text-lg font-semibold text-white light:text-gray-900 mb-4">Ressources</h3>
|
| 242 |
+
<ul class="space-y-3 text-gray-400">
|
| 243 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 244 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 245 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 246 |
+
</ul>
|
| 247 |
+
</div>
|
| 248 |
+
|
| 249 |
+
</div>
|
| 250 |
+
|
| 251 |
+
<div class="mt-10 pt-6 border-t border-gray-800 light:border-gray-300 text-center text-gray-500 text-sm">
|
| 252 |
+
© 2025 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 253 |
+
</div>
|
| 254 |
+
</div>
|
| 255 |
+
</footer>
|
| 256 |
+
|
| 257 |
+
</body>
|
| 258 |
+
</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,401 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>Tarifs - Nexus Pro</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 |
+
/* Assure une meilleure compatibilité responsive pour la grille */
|
| 12 |
+
.pricing-grid {
|
| 13 |
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
/* Variables de Thème - Couleurs Noir Foncé (Mode Sombre par défaut) */
|
| 17 |
+
:root, html.dark {
|
| 18 |
+
--bg-page: #181818; /* Noir très foncé, pas de bleu marine */
|
| 19 |
+
--bg-card: #282828;
|
| 20 |
+
--text-main: #EAEAEA;
|
| 21 |
+
--text-secondary: #B0B0B0;
|
| 22 |
+
--border-color: #404040;
|
| 23 |
+
--shadow-color: rgba(0, 0, 0, 0.5);
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
/* Mode Clair */
|
| 27 |
+
html.light {
|
| 28 |
+
--bg-page: #F5F5F5;
|
| 29 |
+
--bg-card: #FFFFFF;
|
| 30 |
+
--text-main: #202020;
|
| 31 |
+
--text-secondary: #5C5C5C;
|
| 32 |
+
--border-color: #E0E0E0;
|
| 33 |
+
--shadow-color: rgba(0, 0, 0, 0.1);
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/* Application des variables */
|
| 37 |
+
body {
|
| 38 |
+
background-color: var(--bg-page);
|
| 39 |
+
color: var(--text-main);
|
| 40 |
+
transition: background-color 0.3s, color 0.3s;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.bg-gray-900 { background-color: var(--bg-page) !important; }
|
| 44 |
+
.text-white { color: var(--text-main) !important; }
|
| 45 |
+
.bg-gray-800, .bg-gray-800\/50 {
|
| 46 |
+
background-color: var(--bg-card) !important;
|
| 47 |
+
box-shadow: 0 4px 6px -1px var(--shadow-color), 0 2px 4px -2px var(--shadow-color);
|
| 48 |
+
}
|
| 49 |
+
.text-gray-400 { color: var(--text-secondary) !important; }
|
| 50 |
+
.border-gray-700, .border-gray-800 { border-color: var(--border-color) !important; }
|
| 51 |
+
.text-gray-300 { color: var(--text-secondary) !important; } /* Utilisation de la même couleur pour uniformité */
|
| 52 |
+
.bg-gray-700 { background-color: #404040 !important; }
|
| 53 |
+
.theme-switch {
|
| 54 |
+
background: none;
|
| 55 |
+
border: none;
|
| 56 |
+
cursor: pointer;
|
| 57 |
+
color: var(--text-main);
|
| 58 |
+
font-size: 24px;
|
| 59 |
+
transition: color 0.2s;
|
| 60 |
+
padding: 0.5rem; /* Espace autour du bouton */
|
| 61 |
+
}
|
| 62 |
+
</style>
|
| 63 |
+
</head>
|
| 64 |
+
<body class="min-h-screen">
|
| 65 |
+
|
| 66 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 67 |
+
|
| 68 |
+
<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;">
|
| 69 |
+
<a href="/" class="text-4xl font-extrabold text-blue-500 tracking-wider mb-4 sm:mb-0">
|
| 70 |
+
NEXUS
|
| 71 |
+
</a>
|
| 72 |
+
<nav class="flex items-center space-x-4">
|
| 73 |
+
<a href="/documentation" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 74 |
+
Documentation
|
| 75 |
+
</a>
|
| 76 |
+
<a href="/a-propos" class="px-4 py-2 text-white hover:text-blue-300 transition duration-200 font-medium">
|
| 77 |
+
À Propos
|
| 78 |
+
</a>
|
| 79 |
+
|
| 80 |
+
<button id="theme-toggle" class="theme-switch" aria-label="Basculer le thème">
|
| 81 |
+
<span class="material-symbols-rounded">light_mode</span>
|
| 82 |
+
</button>
|
| 83 |
+
|
| 84 |
+
{% if is_logged_in %}
|
| 85 |
+
<a href="/dashboard" class="px-4 py-2 bg-blue-600 border border-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 86 |
+
Dashboard
|
| 87 |
+
</a>
|
| 88 |
+
{% else %}
|
| 89 |
+
<a href="/connexion" class="px-4 py-2 bg-blue-600 border border-blue-600 hover:bg-blue-700 font-medium transition duration-200">
|
| 90 |
+
Connexion
|
| 91 |
+
</a>
|
| 92 |
+
{% endif %}
|
| 93 |
+
</nav>
|
| 94 |
+
</header>
|
| 95 |
+
|
| 96 |
+
<main class="space-y-12">
|
| 97 |
+
|
| 98 |
+
<section class="text-center p-8 bg-gray-800/50 shadow-lg">
|
| 99 |
+
<h1 class="text-5xl font-extrabold text-white mb-4 leading-tight">
|
| 100 |
+
Plans de Tarification
|
| 101 |
+
</h1>
|
| 102 |
+
<p class="text-xl text-gray-300 max-w-3xl mx-auto">
|
| 103 |
+
Sécurité robuste et évolutive. Choisissez le plan adapté à votre nombre d'utilisateurs.
|
| 104 |
+
</p>
|
| 105 |
+
|
| 106 |
+
<div class="mt-8 flex justify-center">
|
| 107 |
+
<div class="inline-flex bg-gray-700 p-1">
|
| 108 |
+
<button id="monthly-btn" class="px-6 py-2 text-sm font-semibold bg-blue-600 text-white shadow-md transition duration-200">
|
| 109 |
+
Mensuel
|
| 110 |
+
</button>
|
| 111 |
+
<button id="annual-btn" class="px-6 py-2 text-sm font-semibold text-gray-300 hover:text-white transition duration-200">
|
| 112 |
+
Annuel (Économisez ~17%)
|
| 113 |
+
</button>
|
| 114 |
+
</div>
|
| 115 |
+
</div>
|
| 116 |
+
|
| 117 |
+
</section>
|
| 118 |
+
|
| 119 |
+
<div class="grid pricing-grid gap-8">
|
| 120 |
+
|
| 121 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-teal-300 flex flex-col">
|
| 122 |
+
<h2 class="text-2xl font-bold text-teal-400 mb-2">Développeur</h2>
|
| 123 |
+
<p class="text-gray-400 mb-6 text-sm">Tests et prototypes.</p>
|
| 124 |
+
|
| 125 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 126 |
+
0<span class="text-xl text-gray-400 price-unit"> €/mois</span>
|
| 127 |
+
</div>
|
| 128 |
+
|
| 129 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 130 |
+
Jusqu'à 500 Comptes Utilisateurs
|
| 131 |
+
</div>
|
| 132 |
+
|
| 133 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 134 |
+
<li class="flex items-start text-gray-300">
|
| 135 |
+
<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>
|
| 136 |
+
Authentification Sécurisée (API & URL)
|
| 137 |
+
</li>
|
| 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 |
+
Logs d'activité de base
|
| 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 |
+
Support par email communautaire
|
| 145 |
+
</li>
|
| 146 |
+
</ul>
|
| 147 |
+
|
| 148 |
+
<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">
|
| 149 |
+
Commencer Gratuitement
|
| 150 |
+
</a>
|
| 151 |
+
</div>
|
| 152 |
+
|
| 153 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-yellow-500 flex flex-col">
|
| 154 |
+
<h2 class="text-2xl font-bold text-yellow-400 mb-2">Standard</h2>
|
| 155 |
+
<p class="text-gray-400 mb-6 text-sm">Premier pas vers la production.</p>
|
| 156 |
+
|
| 157 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 158 |
+
<span class="monthly-price">5</span><span class="annual-price hidden">50</span><span class="text-xl text-gray-400 price-unit"> €/mois</span>
|
| 159 |
+
</div>
|
| 160 |
+
|
| 161 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 162 |
+
Jusqu'à 1 000 Comptes Utilisateurs
|
| 163 |
+
</div>
|
| 164 |
+
|
| 165 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 166 |
+
<li class="flex items-start text-gray-300">
|
| 167 |
+
<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>
|
| 168 |
+
Authentification Sécurisée
|
| 169 |
+
</li>
|
| 170 |
+
<li class="flex items-start text-gray-300">
|
| 171 |
+
<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>
|
| 172 |
+
Logs d'activité avancés
|
| 173 |
+
</li>
|
| 174 |
+
<li class="flex items-start text-gray-300">
|
| 175 |
+
<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>
|
| 176 |
+
Support par email standard (24-48h)
|
| 177 |
+
</li>
|
| 178 |
+
<li class="flex items-start text-gray-300">
|
| 179 |
+
<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>
|
| 180 |
+
Option de dépassement ($/100 comptes)
|
| 181 |
+
</li>
|
| 182 |
+
</ul>
|
| 183 |
+
|
| 184 |
+
<a href="/profile/upgrade" 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">
|
| 185 |
+
Choisir Standard
|
| 186 |
+
</a>
|
| 187 |
+
</div>
|
| 188 |
+
|
| 189 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-blue-500 flex flex-col relative">
|
| 190 |
+
<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>
|
| 191 |
+
<h2 class="text-2xl font-bold text-blue-400 mb-2">Professionnel</h2>
|
| 192 |
+
<p class="text-gray-400 mb-6 text-sm">Croissance et haute disponibilité.</p>
|
| 193 |
+
|
| 194 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 195 |
+
<span class="monthly-price">10</span><span class="annual-price hidden">100</span><span class="text-xl text-gray-400 price-unit"> €/mois</span>
|
| 196 |
+
</div>
|
| 197 |
+
|
| 198 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 199 |
+
Jusqu'à 2 000 Comptes Utilisateurs
|
| 200 |
+
</div>
|
| 201 |
+
|
| 202 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 203 |
+
<li class="flex items-start text-gray-300">
|
| 204 |
+
<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>
|
| 205 |
+
Monitoring et Alertes en Temps Réel
|
| 206 |
+
</li>
|
| 207 |
+
<li class="flex items-start text-gray-300">
|
| 208 |
+
<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>
|
| 209 |
+
Logs API Détaillés (Accès à `/api-logs`)
|
| 210 |
+
</li>
|
| 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 |
+
Support Prioritaire (24h)
|
| 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 |
+
Option de dépassement ($/100 comptes)
|
| 218 |
+
</li>
|
| 219 |
+
</ul>
|
| 220 |
+
|
| 221 |
+
<a href="/profile/upgrade" 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">
|
| 222 |
+
Passer au Plan Pro
|
| 223 |
+
</a>
|
| 224 |
+
</div>
|
| 225 |
+
|
| 226 |
+
<div class="bg-gray-800 p-6 shadow-2xl border-t-4 border-red-500 flex flex-col">
|
| 227 |
+
<h2 class="text-2xl font-bold text-red-400 mb-2">Entreprise</h2>
|
| 228 |
+
<p class="text-gray-400 mb-6 text-sm">Solutions haut de gamme et grandes équipes.</p>
|
| 229 |
+
|
| 230 |
+
<div class="text-4xl font-extrabold text-white mb-8">
|
| 231 |
+
<span class="monthly-price">Sur Devis</span>
|
| 232 |
+
</div>
|
| 233 |
+
|
| 234 |
+
<div class="text-lg font-semibold text-white mb-4 border-b border-gray-700 pb-2">
|
| 235 |
+
Comptes Utilisateurs Illimités
|
| 236 |
+
</div>
|
| 237 |
+
|
| 238 |
+
<ul class="space-y-3 flex-grow text-sm">
|
| 239 |
+
<li class="flex items-start text-gray-300">
|
| 240 |
+
<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>
|
| 241 |
+
Garantie de Niveau de Service (SLA)
|
| 242 |
+
</li>
|
| 243 |
+
<li class="flex items-start text-gray-300">
|
| 244 |
+
<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>
|
| 245 |
+
Authentification Unique (SSO)
|
| 246 |
+
</li>
|
| 247 |
+
<li class="flex items-start text-gray-300">
|
| 248 |
+
<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>
|
| 249 |
+
Gestion des Accès Privilégiés
|
| 250 |
+
</li>
|
| 251 |
+
<li class="flex items-start text-gray-300">
|
| 252 |
+
<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>
|
| 253 |
+
Support Dédicacé 24/7
|
| 254 |
+
</li>
|
| 255 |
+
</ul>
|
| 256 |
+
|
| 257 |
+
<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">
|
| 258 |
+
Contacter les Ventes
|
| 259 |
+
</a>
|
| 260 |
+
</div>
|
| 261 |
+
</div>
|
| 262 |
+
|
| 263 |
+
</main>
|
| 264 |
+
|
| 265 |
+
<footer class="mt-12 pt-6 border-t border-gray-700 text-center text-gray-500 text-sm">
|
| 266 |
+
© 2025 Nexus. Tarifs et Plans de Service.
|
| 267 |
+
</footer>
|
| 268 |
+
</div>
|
| 269 |
+
|
| 270 |
+
<script>
|
| 271 |
+
const monthlyBtn = document.getElementById('monthly-btn');
|
| 272 |
+
const annualBtn = document.getElementById('annual-btn');
|
| 273 |
+
const monthlyPrices = document.querySelectorAll('.monthly-price');
|
| 274 |
+
const annualPrices = document.querySelectorAll('.annual-price');
|
| 275 |
+
const priceUnits = document.querySelectorAll('.price-unit');
|
| 276 |
+
|
| 277 |
+
// Logique de bascule du mode sombre/clair
|
| 278 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 279 |
+
const htmlElement = document.documentElement;
|
| 280 |
+
const iconElement = themeToggle.querySelector('.material-symbols-rounded');
|
| 281 |
+
|
| 282 |
+
// Charger le thème depuis le localStorage
|
| 283 |
+
const savedTheme = localStorage.getItem('theme');
|
| 284 |
+
if (savedTheme === 'light') {
|
| 285 |
+
htmlElement.classList.remove('dark');
|
| 286 |
+
htmlElement.classList.add('light');
|
| 287 |
+
iconElement.textContent = 'dark_mode';
|
| 288 |
+
} else {
|
| 289 |
+
// Dark mode par défaut si rien n'est sauvegardé ou 'dark'
|
| 290 |
+
htmlElement.classList.add('dark');
|
| 291 |
+
htmlElement.classList.remove('light');
|
| 292 |
+
iconElement.textContent = 'light_mode';
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
themeToggle.addEventListener('click', () => {
|
| 296 |
+
if (htmlElement.classList.contains('light')) {
|
| 297 |
+
htmlElement.classList.remove('light');
|
| 298 |
+
htmlElement.classList.add('dark');
|
| 299 |
+
localStorage.setItem('theme', 'dark');
|
| 300 |
+
iconElement.textContent = 'light_mode';
|
| 301 |
+
} else {
|
| 302 |
+
htmlElement.classList.add('light');
|
| 303 |
+
htmlElement.classList.remove('dark');
|
| 304 |
+
localStorage.setItem('theme', 'light');
|
| 305 |
+
iconElement.textContent = 'dark_mode';
|
| 306 |
+
}
|
| 307 |
+
});
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
// Fonction pour mettre à jour l'affichage des tarifs
|
| 311 |
+
function updatePricing(isAnnual) {
|
| 312 |
+
monthlyBtn.classList.remove('bg-blue-600', 'text-white');
|
| 313 |
+
monthlyBtn.classList.add('text-gray-300', 'hover:text-white');
|
| 314 |
+
annualBtn.classList.remove('bg-blue-600', 'text-white');
|
| 315 |
+
annualBtn.classList.add('text-gray-300', 'hover:text-white');
|
| 316 |
+
|
| 317 |
+
if (isAnnual) {
|
| 318 |
+
annualBtn.classList.add('bg-blue-600', 'text-white');
|
| 319 |
+
annualBtn.classList.remove('text-gray-300', 'hover:text-white');
|
| 320 |
+
monthlyPrices.forEach(el => el.classList.add('hidden'));
|
| 321 |
+
annualPrices.forEach(el => el.classList.remove('hidden'));
|
| 322 |
+
priceUnits.forEach(el => el.textContent = ' €/an');
|
| 323 |
+
// Gérer le cas du plan Développeur
|
| 324 |
+
document.querySelector('.pricing-grid > div:first-child .price-unit').textContent = ' €/an';
|
| 325 |
+
|
| 326 |
+
} else {
|
| 327 |
+
monthlyBtn.classList.add('bg-blue-600', 'text-white');
|
| 328 |
+
monthlyBtn.classList.remove('text-gray-300', 'hover:text-white');
|
| 329 |
+
monthlyPrices.forEach(el => el.classList.remove('hidden'));
|
| 330 |
+
annualPrices.forEach(el => el.classList.add('hidden'));
|
| 331 |
+
priceUnits.forEach(el => el.textContent = ' €/mois');
|
| 332 |
+
// Gérer le cas du plan Développeur
|
| 333 |
+
document.querySelector('.pricing-grid > div:first-child .price-unit').textContent = ' €/mois';
|
| 334 |
+
}
|
| 335 |
+
// Gérer le prix "Sur Devis" du plan Entreprise
|
| 336 |
+
document.querySelector('.pricing-grid > div:last-child .price-unit').textContent = '';
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
// Événements Tarification
|
| 340 |
+
monthlyBtn.addEventListener('click', () => updatePricing(false));
|
| 341 |
+
annualBtn.addEventListener('click', () => updatePricing(true));
|
| 342 |
+
|
| 343 |
+
// Initialisation Tarification au chargement
|
| 344 |
+
updatePricing(false);
|
| 345 |
+
</script>
|
| 346 |
+
|
| 347 |
+
<footer class="mt-16 border-t border-gray-700 bg-gray-900" style="background-color: var(--bg-card); border-color: var(--border-color);">
|
| 348 |
+
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-7xl">
|
| 349 |
+
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 text-sm">
|
| 350 |
+
|
| 351 |
+
<div class="col-span-2 lg:col-span-1">
|
| 352 |
+
<a href="/" class="text-3xl font-extrabold text-blue-500 tracking-wider">NEXUS</a>
|
| 353 |
+
<p class="mt-3 text-gray-400">
|
| 354 |
+
L'infrastructure API qui propulse votre avenir technologique.
|
| 355 |
+
</p>
|
| 356 |
+
<div class="mt-4 flex space-x-4">
|
| 357 |
+
<a href="#" class="text-gray-400 hover:text-blue-500 transition duration-200">
|
| 358 |
+
<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>
|
| 359 |
+
</a>
|
| 360 |
+
</div>
|
| 361 |
+
</div>
|
| 362 |
+
|
| 363 |
+
<div>
|
| 364 |
+
<h3 class="text-lg font-semibold text-white mb-4">Plateforme</h3>
|
| 365 |
+
<ul class="space-y-3 text-gray-400">
|
| 366 |
+
<li><a href="/tarifs" class="hover:text-blue-500 transition duration-200">Tarifs</a></li>
|
| 367 |
+
<li><a href="/documentation" class="hover:text-blue-500 transition duration-200">Documentation</a></li>
|
| 368 |
+
<li><a href="/connexion" class="hover:text-blue-500 transition duration-200">Connexion</a></li>
|
| 369 |
+
<li><a href="/support" class="hover:text-blue-500 transition duration-200">Support</a></li>
|
| 370 |
+
</ul>
|
| 371 |
+
</div>
|
| 372 |
+
|
| 373 |
+
<div>
|
| 374 |
+
<h3 class="text-lg font-semibold text-white mb-4">Légal</h3>
|
| 375 |
+
<ul class="space-y-3 text-gray-400">
|
| 376 |
+
<li><a href="/politique-confidentialite" class="hover:text-blue-500 transition duration-200">Politique de Confidentialité</a></li>
|
| 377 |
+
<li><a href="/mentions-legales" class="hover:text-blue-500 transition duration-200">Mentions Légales</a></li>
|
| 378 |
+
<li><a href="/conditions-utilisation" class="hover:text-blue-500 transition duration-200">Conditions d'Utilisation</a></li>
|
| 379 |
+
<li><a href="/a-propos" class="hover:text-blue-500 transition duration-200">À Propos</a></li>
|
| 380 |
+
</ul>
|
| 381 |
+
</div>
|
| 382 |
+
|
| 383 |
+
<div class="col-span-2 md:col-span-1">
|
| 384 |
+
<h3 class="text-lg font-semibold text-white mb-4">Ressources</h3>
|
| 385 |
+
<ul class="space-y-3 text-gray-400">
|
| 386 |
+
<li><a href="mailto:support@nexus.com" class="hover:text-blue-500 transition duration-200">Contact Email</a></li>
|
| 387 |
+
<li><a href="/dashboard" class="hover:text-blue-500 transition duration-200">Espace Client</a></li>
|
| 388 |
+
<li><a href="/api-logs" class="hover:text-blue-500 transition duration-200">Statut API</a></li>
|
| 389 |
+
</ul>
|
| 390 |
+
</div>
|
| 391 |
+
|
| 392 |
+
</div>
|
| 393 |
+
|
| 394 |
+
<div class="mt-10 pt-6 border-t border-gray-800 text-center text-gray-500 text-sm" style="border-color: var(--border-color);">
|
| 395 |
+
© 2024 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
|
| 396 |
+
</div>
|
| 397 |
+
</div>
|
| 398 |
+
</footer>
|
| 399 |
+
|
| 400 |
+
</body>
|
| 401 |
+
</html>
|