ernestmindres commited on
Commit
88d3a44
·
verified ·
1 Parent(s): 9f69ded

Upload 15 files

Browse files
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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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 &quot;https://api.nexus-pro.com/v1/auth/register&quot; \
100
+ -H &quot;X-API-KEY: VOTRE_CLE_API_SECRETE&quot; \
101
+ -H &quot;Content-Type: application/json&quot; \
102
+ -d '{
103
+ &quot;email&quot;: &quot;utilisateur@exemple.com&quot;,
104
+ &quot;password&quot;: &quot;motdepassefort123&quot;
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 &quot;https://api.nexus-pro.com/v1/auth/login&quot; \
149
+ -H &quot;X-API-KEY: VOTRE_CLE_API_SECRETE&quot; \
150
+ -H &quot;Content-Type: application/json&quot; \
151
+ -d '{
152
+ &quot;email&quot;: &quot;utilisateur@exemple.com&quot;,
153
+ &quot;password&quot;: &quot;motdepassefort123&quot;
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 &quot;https://api.nexus-pro.com/v1/auth/user&quot; \
190
+ -H &quot;Authorization: Bearer VOTRE_TOKEN_JWT&quot;</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 &quot;https://api.nexus-pro.com/v1/auth/user/update&quot; \
215
+ -H &quot;Authorization: Bearer VOTRE_TOKEN_JWT&quot; \
216
+ -H &quot;Content-Type: application/json&quot; \
217
+ -d '{
218
+ &quot;first_name&quot;: &quot;Jean&quot;,
219
+ &quot;last_name&quot;: &quot;Dupont&quot;
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
+ &quot;error&quot;: true,
251
+ &quot;status_code&quot;: 401,
252
+ &quot;message&quot;: &quot;Token JWT manquant ou invalide. Veuillez vous reconnecter.&quot;
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
+ &copy; 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">&lt;?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
+ ?&gt;</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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 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
+ &copy; 2024 Nexus. Tous droits réservés. Construit pour l'ère des microservices.
396
+ </div>
397
+ </div>
398
+ </footer>
399
+
400
+ </body>
401
+ </html>