Mohit0199 commited on
Commit
cf25b7e
Β·
verified Β·
1 Parent(s): b64250b

I want you to modify or extend this project with the following features:

Browse files

---

### πŸ” 1. Simple Authentication
- Add a clean, minimal login/register modal using TailwindCSS.
- Users can create an account (username + password) or log in with an existing one.
- When a user logs in successfully, show a welcome message like β€œWelcome back, <username>”.
- Store the current logged-in user in `localStorage` as `chatRouterUser`.

---

### πŸ’¬ 2. Chat History Per User
- Each logged-in user should have their own chat history stored in `localStorage` using a key like `chatHistory_<username>`.
- When they log in, their past conversations should load automatically.
- Modify the `addMessage()` function so every message (user + assistant) is saved in that user’s chat history.
- Add a **β€œNew Chat”** button (beside Settings) that clears only the current chat for that user and shows a system message β€œπŸ†• New chat started.”

---

### ⚠️ 3. Handle Paid Model Errors Gracefully
- When the selected OpenRouter model requires payment (like Claude or GPT-4), it currently throws a JSON error.
- Instead of showing a raw error, display a friendly message:
> β€œβš οΈ This model requires a paid OpenRouter plan. Please select a free model to continue.”
- Detect this by checking if the error message includes β€œpayment” or β€œunauthorized”.

---

### 🎨 4. Small UI Touches
- Add a login/logout button in the header.
- When logged out, disable message sending and show a system message β€œPlease log in to start chatting.”
- Keep the theme, settings modal, and layout the same as the original ChatRouter design.

---

### βš™οΈ 5. Behavior Summary
- If no user is logged in β†’ show login modal first.
- After login β†’ load their history and enable full chat.
- When a new chat starts β†’ only clear the conversation UI and the stored history for that user.
- On logout β†’ clear only the session (keep users stored).

---

### πŸš€ Expected Output
Generate the complete updated `index.html` (or equivalent) with all these features implemented and explained with clean, well-commented code.

Make sure everything runs locally without a backend β€” just using `localStorage`, TailwindCSS, and JS.

---

### πŸ’‘ Important
Do not alter the original API integration logic with OpenRouter or the existing visual style β€” only extend it with the above features.

Files changed (1) hide show
  1. index.html +201 -17
index.html CHANGED
@@ -48,14 +48,50 @@
48
  <i data-feather="cpu" class="w-8 h-8 text-indigo-300"></i>
49
  <h1 class="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-indigo-300 to-purple-300">ChatRouter</h1>
50
  </div>
51
- <button id="settingsBtn" class="flex items-center space-x-2 bg-indigo-800 hover:bg-indigo-700 px-4 py-2 rounded-lg transition-all">
52
- <i data-feather="settings" class="w-5 h-5"></i>
53
- <span>Settings</span>
54
- </button>
 
 
 
 
 
 
 
 
 
 
55
  </header>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  <!-- Settings Modal -->
58
- <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
59
  <div class="bg-gray-800 rounded-xl p-6 w-full max-w-md">
60
  <div class="flex justify-between items-center mb-4">
61
  <h2 class="text-xl font-bold">Chat Settings</h2>
@@ -133,9 +169,19 @@
133
 
134
  <script>
135
  feather.replace();
136
-
137
  // DOM Elements
138
- const settingsBtn = document.getElementById('settingsBtn');
 
 
 
 
 
 
 
 
 
 
 
139
  const settingsModal = document.getElementById('settingsModal');
140
  const closeSettings = document.getElementById('closeSettings');
141
  const apiKeyInput = document.getElementById('apiKeyInput');
@@ -147,8 +193,84 @@
147
  const typingIndicator = document.getElementById('typingIndicator');
148
  const modelIndicator = document.getElementById('modelIndicator');
149
  const themeBtns = document.querySelectorAll('.theme-btn');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  // Load saved settings
151
- async function loadSettings() {
152
  const savedApiKey = localStorage.getItem('chatRouterApiKey');
153
  const savedModel = localStorage.getItem('chatRouterModel');
154
  const savedTheme = localStorage.getItem('chatRouterTheme') || 'indigo';
@@ -279,7 +401,6 @@
279
  messageInput.style.height = 'auto';
280
  messageInput.style.height = (messageInput.scrollHeight) + 'px';
281
  });
282
-
283
  // Add message to chat
284
  function addMessage(role, content) {
285
  const messageDiv = document.createElement('div');
@@ -292,10 +413,25 @@
292
  messageDiv.appendChild(bubble);
293
  chatContainer.appendChild(messageDiv);
294
  chatContainer.scrollTop = chatContainer.scrollHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
 
297
  // Send message to OpenRouter
298
- async function sendMessage() {
299
  const message = messageInput.value.trim();
300
  if (!message) return;
301
 
@@ -342,9 +478,56 @@
342
  typingIndicator.classList.add('hidden');
343
  }
344
  }
345
-
346
  // Event listeners
347
- messageInput.addEventListener('keydown', (e) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  if (e.key === 'Enter' && !e.shiftKey) {
349
  e.preventDefault();
350
  sendMessage();
@@ -352,16 +535,17 @@
352
  });
353
 
354
  sendBtn.addEventListener('click', sendMessage);
355
-
356
  // Initialize
357
  loadSettings();
358
-
359
  // Welcome message
360
  setTimeout(() => {
361
- if (!localStorage.getItem('chatRouterApiKey')) {
362
- addMessage('system', 'Welcome to ChatRouter! Please enter your OpenRouter API key in settings to begin.');
 
 
363
  }
364
  }, 1000);
365
- </script>
366
  </body>
367
  </html>
 
48
  <i data-feather="cpu" class="w-8 h-8 text-indigo-300"></i>
49
  <h1 class="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-indigo-300 to-purple-300">ChatRouter</h1>
50
  </div>
51
+ <div class="flex items-center space-x-2">
52
+ <button id="newChatBtn" class="flex items-center space-x-2 bg-indigo-800 hover:bg-indigo-700 px-4 py-2 rounded-lg transition-all">
53
+ <i data-feather="plus" class="w-5 h-5"></i>
54
+ <span>New Chat</span>
55
+ </button>
56
+ <button id="settingsBtn" class="flex items-center space-x-2 bg-indigo-800 hover:bg-indigo-700 px-4 py-2 rounded-lg transition-all">
57
+ <i data-feather="settings" class="w-5 h-5"></i>
58
+ <span>Settings</span>
59
+ </button>
60
+ <button id="authBtn" class="flex items-center space-x-2 bg-indigo-800 hover:bg-indigo-700 px-4 py-2 rounded-lg transition-all">
61
+ <i data-feather="user" class="w-5 h-5"></i>
62
+ <span>Login</span>
63
+ </button>
64
+ </div>
65
  </header>
66
+ <!-- Auth Modal -->
67
+ <div id="authModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
68
+ <div class="bg-gray-800 rounded-xl p-6 w-full max-w-md">
69
+ <div class="flex justify-between items-center mb-4">
70
+ <h2 class="text-xl font-bold" id="authModalTitle">Login</h2>
71
+ <button id="closeAuth" class="text-gray-400 hover:text-white">
72
+ <i data-feather="x"></i>
73
+ </button>
74
+ </div>
75
+ <div id="authForm" class="space-y-4">
76
+ <div id="registerFields" class="hidden">
77
+ <label class="block text-sm font-medium mb-1">Username</label>
78
+ <input type="text" id="regUsername" placeholder="Choose a username" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
79
+ </div>
80
+ <div>
81
+ <label class="block text-sm font-medium mb-1">Password</label>
82
+ <input type="password" id="authPassword" placeholder="Enter your password" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500">
83
+ </div>
84
+ <button id="authActionBtn" class="w-full bg-indigo-600 hover:bg-indigo-500 text-white py-2 rounded-lg transition-colors">Login</button>
85
+ <div class="text-center text-sm">
86
+ <span id="authToggleText">Don't have an account? </span>
87
+ <button id="authToggleBtn" class="text-indigo-400 hover:text-indigo-300">Register</button>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
 
93
  <!-- Settings Modal -->
94
+ <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
95
  <div class="bg-gray-800 rounded-xl p-6 w-full max-w-md">
96
  <div class="flex justify-between items-center mb-4">
97
  <h2 class="text-xl font-bold">Chat Settings</h2>
 
169
 
170
  <script>
171
  feather.replace();
 
172
  // DOM Elements
173
+ const authBtn = document.getElementById('authBtn');
174
+ const authModal = document.getElementById('authModal');
175
+ const authModalTitle = document.getElementById('authModalTitle');
176
+ const closeAuth = document.getElementById('closeAuth');
177
+ const regUsername = document.getElementById('regUsername');
178
+ const authPassword = document.getElementById('authPassword');
179
+ const authActionBtn = document.getElementById('authActionBtn');
180
+ const authToggleBtn = document.getElementById('authToggleBtn');
181
+ const authToggleText = document.getElementById('authToggleText');
182
+ const registerFields = document.getElementById('registerFields');
183
+ const newChatBtn = document.getElementById('newChatBtn');
184
+ const settingsBtn = document.getElementById('settingsBtn');
185
  const settingsModal = document.getElementById('settingsModal');
186
  const closeSettings = document.getElementById('closeSettings');
187
  const apiKeyInput = document.getElementById('apiKeyInput');
 
193
  const typingIndicator = document.getElementById('typingIndicator');
194
  const modelIndicator = document.getElementById('modelIndicator');
195
  const themeBtns = document.querySelectorAll('.theme-btn');
196
+ // User management
197
+ let isRegistering = false;
198
+
199
+ function updateAuthUI() {
200
+ const loggedInUser = localStorage.getItem('chatRouterUser');
201
+ if (loggedInUser) {
202
+ authBtn.innerHTML = `<i data-feather="log-out" class="w-5 h-5"></i><span>Logout</span>`;
203
+ authBtn.dataset.state = 'logout';
204
+ document.querySelector('#newChatBtn').disabled = false;
205
+ document.querySelector('#settingsBtn').disabled = false;
206
+ sendBtn.disabled = false;
207
+ } else {
208
+ authBtn.innerHTML = `<i data-feather="user" class="w-5 h-5"></i><span>Login</span>`;
209
+ authBtn.dataset.state = 'login';
210
+ document.querySelector('#newChatBtn').disabled = true;
211
+ document.querySelector('#settingsBtn').disabled = true;
212
+ sendBtn.disabled = true;
213
+ showAuthModal();
214
+ }
215
+ feather.replace();
216
+ }
217
+
218
+ function showAuthModal(register = false) {
219
+ isRegistering = register;
220
+ authModalTitle.textContent = register ? 'Register' : 'Login';
221
+ authActionBtn.textContent = register ? 'Register' : 'Login';
222
+ authToggleText.textContent = register ? 'Already have an account? ' : 'Don\'t have an account? ';
223
+ authToggleBtn.textContent = register ? 'Login' : 'Register';
224
+ registerFields.classList.toggle('hidden', !register);
225
+ authModal.classList.remove('hidden');
226
+ }
227
+
228
+ function loginUser(username, password) {
229
+ // Simple auth - store user in localStorage
230
+ localStorage.setItem('chatRouterUser', username);
231
+ localStorage.setItem(`chatRouterPass_${username}`, password); // Not secure for production!
232
+ updateAuthUI();
233
+
234
+ // Load user's chat history
235
+ loadChatHistory(username);
236
+
237
+ // Show welcome message
238
+ addMessage('system', `Welcome back, ${username}!`);
239
+ }
240
+
241
+ function logoutUser() {
242
+ const username = localStorage.getItem('chatRouterUser');
243
+ localStorage.removeItem('chatRouterUser');
244
+ updateAuthUI();
245
+
246
+ // Clear current chat
247
+ chatContainer.innerHTML = '';
248
+ addMessage('system', 'Please log in to start chatting.');
249
+ }
250
+
251
+ function loadChatHistory(username) {
252
+ const history = localStorage.getItem(`chatHistory_${username}`);
253
+ if (history) {
254
+ chatContainer.innerHTML = history;
255
+ chatContainer.scrollTop = chatContainer.scrollHeight;
256
+ }
257
+ }
258
+
259
+ function saveChatHistory(username) {
260
+ localStorage.setItem(`chatHistory_${username}`, chatContainer.innerHTML);
261
+ }
262
+
263
+ function clearCurrentChat() {
264
+ const username = localStorage.getItem('chatRouterUser');
265
+ if (username) {
266
+ chatContainer.innerHTML = '';
267
+ addMessage('system', 'πŸ†• New chat started.');
268
+ saveChatHistory(username);
269
+ }
270
+ }
271
+
272
  // Load saved settings
273
+ async function loadSettings() {
274
  const savedApiKey = localStorage.getItem('chatRouterApiKey');
275
  const savedModel = localStorage.getItem('chatRouterModel');
276
  const savedTheme = localStorage.getItem('chatRouterTheme') || 'indigo';
 
401
  messageInput.style.height = 'auto';
402
  messageInput.style.height = (messageInput.scrollHeight) + 'px';
403
  });
 
404
  // Add message to chat
405
  function addMessage(role, content) {
406
  const messageDiv = document.createElement('div');
 
413
  messageDiv.appendChild(bubble);
414
  chatContainer.appendChild(messageDiv);
415
  chatContainer.scrollTop = chatContainer.scrollHeight;
416
+
417
+ // Save to user's chat history
418
+ const username = localStorage.getItem('chatRouterUser');
419
+ if (username) {
420
+ saveChatHistory(username);
421
+ }
422
+ }
423
+ // Handle API errors gracefully
424
+ function handleApiError(error) {
425
+ const errorMsg = error.message.toLowerCase();
426
+ if (errorMsg.includes('payment') || errorMsg.includes('unauthorized')) {
427
+ addMessage('system', '⚠️ This model requires a paid OpenRouter plan. Please select a free model to continue.');
428
+ } else {
429
+ addMessage('system', `Error: ${error.message}`);
430
+ }
431
  }
432
 
433
  // Send message to OpenRouter
434
+ async function sendMessage() {
435
  const message = messageInput.value.trim();
436
  if (!message) return;
437
 
 
478
  typingIndicator.classList.add('hidden');
479
  }
480
  }
 
481
  // Event listeners
482
+ authBtn.addEventListener('click', () => {
483
+ if (authBtn.dataset.state === 'logout') {
484
+ logoutUser();
485
+ } else {
486
+ showAuthModal();
487
+ }
488
+ });
489
+
490
+ closeAuth.addEventListener('click', () => {
491
+ authModal.classList.add('hidden');
492
+ });
493
+
494
+ authToggleBtn.addEventListener('click', () => {
495
+ showAuthModal(!isRegistering);
496
+ });
497
+
498
+ authActionBtn.addEventListener('click', () => {
499
+ if (isRegistering) {
500
+ const username = regUsername.value.trim();
501
+ const password = authPassword.value.trim();
502
+
503
+ if (!username || !password) {
504
+ alert('Please enter both username and password');
505
+ return;
506
+ }
507
+
508
+ if (localStorage.getItem(`chatRouterPass_${username}`)) {
509
+ alert('Username already exists');
510
+ return;
511
+ }
512
+
513
+ loginUser(username, password);
514
+ } else {
515
+ const username = regUsername.value.trim();
516
+ const password = authPassword.value.trim();
517
+ const storedPass = localStorage.getItem(`chatRouterPass_${username}`);
518
+
519
+ if (!storedPass || storedPass !== password) {
520
+ alert('Invalid username or password');
521
+ return;
522
+ }
523
+
524
+ loginUser(username, password);
525
+ }
526
+ authModal.classList.add('hidden');
527
+ });
528
+
529
+ newChatBtn.addEventListener('click', clearCurrentChat);
530
+ messageInput.addEventListener('keydown', (e) => {
531
  if (e.key === 'Enter' && !e.shiftKey) {
532
  e.preventDefault();
533
  sendMessage();
 
535
  });
536
 
537
  sendBtn.addEventListener('click', sendMessage);
 
538
  // Initialize
539
  loadSettings();
540
+ updateAuthUI();
541
  // Welcome message
542
  setTimeout(() => {
543
+ if (!localStorage.getItem('chatRouterUser')) {
544
+ addMessage('system', 'Welcome to ChatRouter! Please log in to start chatting.');
545
+ } else if (!localStorage.getItem('chatRouterApiKey')) {
546
+ addMessage('system', 'Please enter your OpenRouter API key in settings to begin.');
547
  }
548
  }, 1000);
549
+ </script>
550
  </body>
551
  </html>