LogitCode commited on
Commit
d20b879
Β·
verified Β·
1 Parent(s): 7e22aeb

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +36 -22
index.html CHANGED
@@ -258,9 +258,9 @@ tailwind.config = {
258
  <div class="relative">
259
  <select id="model-select" class="w-full bg-ash border border-mist rounded-md px-3 py-2 pr-7 text-xs font-mono text-cream focus:border-amber transition-colors cursor-pointer" onchange="saveSettings()">
260
  <optgroup label='Openrouter'>
 
261
  <option value='openrouter/hunter-alpha'>Hunter Alpha </option>
262
  <option value='openrouter/healer-alpha'>Healer Alpha </option>
263
- <option value='openrouter/free'>Free Models Router </option>
264
  </optgroup>
265
  <optgroup label='Nvidia'>
266
  <option value='nvidia/nemotron-3-super-120b-a12b:free'>NVIDIA: Nemotron 3 Super (free) </option>
@@ -577,26 +577,25 @@ let chats = {}; // { id: { id, title, messages: [], createdAt } }
577
 
578
  // ── Init ───────────────────────────────────────────────────────────────────
579
  function init() {
580
- if (localStorage.getItem('nexus_privacy_seen')) dismissPrivacyNotice();
581
 
582
- if (localStorage.getItem('nexus_theme') === 'light') toggleTheme(); // ← add this
583
 
584
  loadSettings();
585
  loadChats();
586
  updateModelBadge();
587
- newChat();
588
  }
589
 
590
  function dismissPrivacyNotice() {
591
  document.getElementById('privacy-modal').remove();
592
- localStorage.setItem('nexus_privacy_seen', '1');
593
  }
594
 
595
  function toggleTheme() {
596
  const isLight = document.body.classList.toggle('light');
597
  document.getElementById('theme-icon-dark').classList.toggle('hidden', isLight);
598
  document.getElementById('theme-icon-light').classList.toggle('hidden', !isLight);
599
- localStorage.setItem('nexus_theme', isLight ? 'light' : 'dark');
600
  document.getElementById('hljs-theme').href = isLight
601
  ? 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css'
602
  : 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css';
@@ -610,13 +609,13 @@ function saveSettings() {
610
  temperature: document.getElementById('temperature').value,
611
  maxTokens: document.getElementById('max-tokens').value,
612
  };
613
- localStorage.setItem('nexus_settings', JSON.stringify(settings));
614
  updateModelBadge();
615
  }
616
 
617
  function loadSettings() {
618
  try {
619
- const s = JSON.parse(localStorage.getItem('nexus_settings') || '{}');
620
  if (s.apiKey) document.getElementById('api-key').value = s.apiKey;
621
  if (s.model) document.getElementById('model-select').value = s.model;
622
  if (s.systemPrompt) document.getElementById('system-prompt').value = s.systemPrompt;
@@ -643,12 +642,12 @@ function toggleKeyVisibility() {
643
  function genId() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 6); }
644
 
645
  function saveChats() {
646
- localStorage.setItem('nexus_chats', JSON.stringify(chats));
647
  }
648
 
649
  function loadChats() {
650
  try {
651
- chats = JSON.parse(localStorage.getItem('nexus_chats') || '{}');
652
  } catch(e) { chats = {}; }
653
  renderConvList();
654
  }
@@ -671,7 +670,9 @@ function switchChat(id) {
671
  renderMessages();
672
  renderConvList();
673
  const chat = chats[id];
674
- document.getElementById('chat-title').textContent = chat.title;
 
 
675
  closeSidebar();
676
  }
677
 
@@ -684,9 +685,11 @@ function deleteChat(id, e) {
684
  }
685
 
686
  function clearCurrentChat() {
687
- if (!currentChatId) return;
688
- chats[currentChatId].messages = [];
689
- chats[currentChatId].title = 'New conversation';
 
 
690
  document.getElementById('chat-title').textContent = 'New conversation';
691
  saveChats();
692
  renderConvList();
@@ -695,6 +698,8 @@ function clearCurrentChat() {
695
 
696
  function renderConvList() {
697
  const list = document.getElementById('conv-list');
 
 
698
  const sorted = Object.values(chats).sort((a,b) => b.createdAt - a.createdAt);
699
  if (sorted.length === 0) {
700
  list.innerHTML = '<div class="text-fog/60 text-xs font-mono px-3 py-2">No conversations yet</div>';
@@ -717,9 +722,10 @@ const msgContentMap = {};
717
 
718
  function renderMessages() {
719
  const container = document.getElementById('messages');
720
- const msgs = chats[currentChatId]?.messages || [];
 
721
 
722
- if (msgs.length === 0) {
723
  container.innerHTML = `<div id="empty-state" class="h-full flex flex-col items-center justify-center text-center py-16">
724
  <div class="font-display text-5xl italic text-cream/20 mb-4 select-none">FlexChat</div>
725
  <div class="text-fog text-sm font-mono max-w-xs">Enter your OpenRouter API key in the sidebar, choose a model, and start a conversation.</div>
@@ -762,7 +768,7 @@ function renderMessage(msg, idx) {
762
  } else {
763
  return `<div class="flex gap-3 items-start">
764
  <div class="w-7 h-7 rounded-md bg-gradient-to-br from-amber to-ember flex items-center justify-center flex-shrink-0 mt-0.5 shadow-md">
765
- <span class="text-ink text-xs font-display font-bold italic">N</span>
766
  </div>
767
  <div class="flex-1 min-w-0 group">
768
  <div class="text-xs font-mono text-ghost mb-1.5">${escHtml(msg.model || 'assistant')}</div>
@@ -810,7 +816,10 @@ async function sendMessage() {
810
  const input = document.getElementById('user-input');
811
  const text = input.value.trim();
812
  if (!text || isStreaming) return;
813
-
 
 
 
814
  const apiKey = document.getElementById('api-key').value.trim();
815
  if (!apiKey) { showError('Please enter your OpenRouter API key in the sidebar.'); return; }
816
 
@@ -855,7 +864,7 @@ async function sendMessage() {
855
  placeholder.className = 'flex gap-3 items-start';
856
  placeholder.innerHTML = `
857
  <div class="w-7 h-7 rounded-md bg-gradient-to-br from-amber to-ember flex items-center justify-center flex-shrink-0 mt-0.5 shadow-md">
858
- <span class="text-ink text-xs font-display font-bold italic">N</span>
859
  </div>
860
  <div class="flex-1 min-w-0">
861
  <div class="text-xs font-mono text-ghost mb-1.5">${escHtml(model.split('/').pop())}</div>
@@ -1041,13 +1050,18 @@ function openSidebar() {
1041
  function closeSidebar() {
1042
  const s = document.getElementById('sidebar');
1043
  const o = document.getElementById('overlay');
 
 
1044
  s.classList.add('-translate-x-full');
1045
- o.classList.add('opacity-0');
1046
- setTimeout(() => o.classList.add('hidden'), 300);
 
 
 
1047
  }
1048
 
1049
  // ── Boot ───────────────────────────────────────────────────────────────────
1050
  init();
1051
  </script>
1052
  </body>
1053
- </html>
 
258
  <div class="relative">
259
  <select id="model-select" class="w-full bg-ash border border-mist rounded-md px-3 py-2 pr-7 text-xs font-mono text-cream focus:border-amber transition-colors cursor-pointer" onchange="saveSettings()">
260
  <optgroup label='Openrouter'>
261
+ <option value='openrouter/free'>Free Models Router </option>
262
  <option value='openrouter/hunter-alpha'>Hunter Alpha </option>
263
  <option value='openrouter/healer-alpha'>Healer Alpha </option>
 
264
  </optgroup>
265
  <optgroup label='Nvidia'>
266
  <option value='nvidia/nemotron-3-super-120b-a12b:free'>NVIDIA: Nemotron 3 Super (free) </option>
 
577
 
578
  // ── Init ───────────────────────────────────────────────────────────────────
579
  function init() {
580
+ if (localStorage.getItem('flexchat_privacy_seen')) dismissPrivacyNotice();
581
 
582
+ if (localStorage.getItem('flexchat_theme') === 'light') toggleTheme(); // ← add this
583
 
584
  loadSettings();
585
  loadChats();
586
  updateModelBadge();
 
587
  }
588
 
589
  function dismissPrivacyNotice() {
590
  document.getElementById('privacy-modal').remove();
591
+ localStorage.setItem('flexchat_privacy_seen', '1');
592
  }
593
 
594
  function toggleTheme() {
595
  const isLight = document.body.classList.toggle('light');
596
  document.getElementById('theme-icon-dark').classList.toggle('hidden', isLight);
597
  document.getElementById('theme-icon-light').classList.toggle('hidden', !isLight);
598
+ localStorage.setItem('flexchat_theme', isLight ? 'light' : 'dark');
599
  document.getElementById('hljs-theme').href = isLight
600
  ? 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css'
601
  : 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css';
 
609
  temperature: document.getElementById('temperature').value,
610
  maxTokens: document.getElementById('max-tokens').value,
611
  };
612
+ localStorage.setItem('flexchat_settings', JSON.stringify(settings));
613
  updateModelBadge();
614
  }
615
 
616
  function loadSettings() {
617
  try {
618
+ const s = JSON.parse(localStorage.getItem('flexchat_settings') || '{}');
619
  if (s.apiKey) document.getElementById('api-key').value = s.apiKey;
620
  if (s.model) document.getElementById('model-select').value = s.model;
621
  if (s.systemPrompt) document.getElementById('system-prompt').value = s.systemPrompt;
 
642
  function genId() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 6); }
643
 
644
  function saveChats() {
645
+ localStorage.setItem('flexchat_chats', JSON.stringify(chats));
646
  }
647
 
648
  function loadChats() {
649
  try {
650
+ chats = JSON.parse(localStorage.getItem('flexchat_chats') || '{}');
651
  } catch(e) { chats = {}; }
652
  renderConvList();
653
  }
 
670
  renderMessages();
671
  renderConvList();
672
  const chat = chats[id];
673
+ if (chat) {
674
+ document.getElementById('chat-title').textContent = chat.title;
675
+ }
676
  closeSidebar();
677
  }
678
 
 
685
  }
686
 
687
  function clearCurrentChat() {
688
+ if (!currentChatId) return;
689
+ const chat = chats[currentChatId];
690
+ if (!chat) return;
691
+ chat.messages = [];
692
+ chat.title = 'New conversation';
693
  document.getElementById('chat-title').textContent = 'New conversation';
694
  saveChats();
695
  renderConvList();
 
698
 
699
  function renderConvList() {
700
  const list = document.getElementById('conv-list');
701
+ if (!list) return;
702
+
703
  const sorted = Object.values(chats).sort((a,b) => b.createdAt - a.createdAt);
704
  if (sorted.length === 0) {
705
  list.innerHTML = '<div class="text-fog/60 text-xs font-mono px-3 py-2">No conversations yet</div>';
 
722
 
723
  function renderMessages() {
724
  const container = document.getElementById('messages');
725
+ const chat = chats[currentChatId];
726
+ const msgs = chat ? chat.messages : [];
727
 
728
+ if (!chat || msgs.length === 0) {
729
  container.innerHTML = `<div id="empty-state" class="h-full flex flex-col items-center justify-center text-center py-16">
730
  <div class="font-display text-5xl italic text-cream/20 mb-4 select-none">FlexChat</div>
731
  <div class="text-fog text-sm font-mono max-w-xs">Enter your OpenRouter API key in the sidebar, choose a model, and start a conversation.</div>
 
768
  } else {
769
  return `<div class="flex gap-3 items-start">
770
  <div class="w-7 h-7 rounded-md bg-gradient-to-br from-amber to-ember flex items-center justify-center flex-shrink-0 mt-0.5 shadow-md">
771
+ <span class="text-ink text-xs font-display font-bold italic">Bot</span>
772
  </div>
773
  <div class="flex-1 min-w-0 group">
774
  <div class="text-xs font-mono text-ghost mb-1.5">${escHtml(msg.model || 'assistant')}</div>
 
816
  const input = document.getElementById('user-input');
817
  const text = input.value.trim();
818
  if (!text || isStreaming) return;
819
+
820
+ if (!currentChatId || !chats[currentChatId]) {
821
+ newChat();
822
+ }
823
  const apiKey = document.getElementById('api-key').value.trim();
824
  if (!apiKey) { showError('Please enter your OpenRouter API key in the sidebar.'); return; }
825
 
 
864
  placeholder.className = 'flex gap-3 items-start';
865
  placeholder.innerHTML = `
866
  <div class="w-7 h-7 rounded-md bg-gradient-to-br from-amber to-ember flex items-center justify-center flex-shrink-0 mt-0.5 shadow-md">
867
+ <span class="text-ink text-xs font-display font-bold italic">Bot</span>
868
  </div>
869
  <div class="flex-1 min-w-0">
870
  <div class="text-xs font-mono text-ghost mb-1.5">${escHtml(model.split('/').pop())}</div>
 
1050
  function closeSidebar() {
1051
  const s = document.getElementById('sidebar');
1052
  const o = document.getElementById('overlay');
1053
+
1054
+ s.removeAttribute('data-open');
1055
  s.classList.add('-translate-x-full');
1056
+
1057
+ o.classList.add('hidden');
1058
+ setTimeout(() => {
1059
+ o.style.display = 'none';
1060
+ }, 300);
1061
  }
1062
 
1063
  // ── Boot ───────────────────────────────────────────────────────────────────
1064
  init();
1065
  </script>
1066
  </body>
1067
+ </html>