xenux4u commited on
Commit
eef5391
·
verified ·
1 Parent(s): 9b7d4c5

Update static/js/script.js

Browse files
Files changed (1) hide show
  1. static/js/script.js +47 -23
static/js/script.js CHANGED
@@ -1,6 +1,6 @@
1
  /**
2
  * ORBIT – Educational Research Assistant
3
- * FULL V-MASTER SCRIPT - DEEP ANALYZED, CACHE BUSTED, FORCED FREE MODELS
4
  */
5
 
6
  document.addEventListener('DOMContentLoaded', () => {
@@ -14,7 +14,7 @@ document.addEventListener('DOMContentLoaded', () => {
14
  let isBusy = false;
15
  let pdfText = ""; let pdfFilename = "";
16
 
17
- // 14 MODEL FREE SESUAI LIST LU
18
  const DEFAULT_OR_MODELS = [
19
  "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
20
  "baidu/cobuddy:free",
@@ -32,21 +32,37 @@ document.addEventListener('DOMContentLoaded', () => {
32
  "meta-llama/llama-3.3-70b-instruct:free"
33
  ];
34
 
35
- // TOAST NOTIFICATION (Sistem Pop-Up Sukses)
36
  function showToast(message, isError = false) {
37
  let toast = $('orbit-toast');
38
  if (!toast) {
39
  toast = document.createElement('div');
40
  toast.id = 'orbit-toast';
 
 
 
 
 
 
 
 
41
  document.body.appendChild(toast);
42
  }
43
- const bgClass = isError ? 'bg-red-500' : 'bg-emerald-500';
44
- toast.className = `fixed top-6 left-1/2 transform -translate-x-1/2 px-5 py-2.5 rounded-full shadow-2xl text-sm font-semibold z-[9999] transition-all duration-300 flex items-center gap-2 text-white ${bgClass}`;
45
- toast.style.opacity = '0';
46
- toast.style.transform = 'translate(-50%, -20px)';
47
- toast.innerHTML = `<span>${message}</span>`;
48
- requestAnimationFrame(() => { toast.style.opacity = '1'; toast.style.transform = 'translate(-50%, 0)'; });
49
- setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translate(-50%, -20px)'; }, 3000);
 
 
 
 
 
 
 
 
50
  }
51
 
52
  // 1. DATA RECOVERY
@@ -79,10 +95,9 @@ document.addEventListener('DOMContentLoaded', () => {
79
  }
80
  });
81
 
82
- // 3. BOOT & INIT (DENGAN CACHE BUSTER API)
83
  async function init() {
84
  try {
85
- // cache: 'no-store' WAJIB biar gak baca API nyangkut
86
  const me = await fetch('/api/me', { cache: 'no-store' });
87
  if(me.status === 401) { window.location.href = '/login'; return; }
88
  if(me.ok) {
@@ -100,12 +115,10 @@ document.addEventListener('DOMContentLoaded', () => {
100
  appSettings.models_agentrouter = safeArr(appSettings.models_agentrouter);
101
  appSettings.models_openai = safeArr(appSettings.models_openai);
102
 
103
- // PAKSA TIMPA MODEL OPENROUTER DENGAN 14 MODEL FREE (Jalan 1x saja)
104
- if (!localStorage.getItem('orbit_force_free_v4')) {
105
  appSettings.models_openrouter = [...DEFAULT_OR_MODELS];
106
- localStorage.setItem('orbit_force_free_v4', 'true');
107
 
108
- // Langsung tembak ke backend biar nyimpen
109
  fetch('/api/settings', {
110
  method: 'POST',
111
  headers: {'Content-Type': 'application/json'},
@@ -299,11 +312,13 @@ document.addEventListener('DOMContentLoaded', () => {
299
  bindAdd('btn-add-ar', 'inp-ar', 'models_agentrouter');
300
  bindAdd('btn-add-oai', 'inp-oai', 'models_openai');
301
 
302
- // SAVE SETTINGS & TOAST & CACHE BUST API
303
  addEvt('btn-save-settings', async () => {
304
  const btn = $('btn-save-settings');
305
  const originalText = btn.textContent;
306
- btn.textContent = "Saving...";
 
 
307
  btn.disabled = true;
308
 
309
  const payload = {
@@ -317,26 +332,35 @@ document.addEventListener('DOMContentLoaded', () => {
317
  models_openai: safeArr(appSettings.models_openai),
318
  current_model: $('model-select').value
319
  };
 
320
  try {
321
  const res = await fetch('/api/settings', {
322
  method: 'POST',
323
  headers: {'Content-Type': 'application/json'},
324
  body: JSON.stringify(payload)
325
  });
 
326
  if(res.ok) {
327
  appSettings = await res.json();
328
  populateModelSelect();
329
- $('settings-modal').classList.add('hidden');
330
- showToast("Settings saved successfully!");
 
 
 
 
 
331
  } else {
332
- throw new Error("Gagal menyimpan ke server");
333
  }
334
  } catch(e) {
335
  console.error(e);
336
  showToast(`Error: ${e.message}`, true);
337
  } finally {
338
- btn.textContent = originalText;
339
- btn.disabled = false;
 
 
340
  }
341
  });
342
 
 
1
  /**
2
  * ORBIT – Educational Research Assistant
3
+ * FULL V-MASTER SCRIPT - TOAST FIXED (VANILLA CSS), BUTTON SPINNER, DEEP ANALYZED
4
  */
5
 
6
  document.addEventListener('DOMContentLoaded', () => {
 
14
  let isBusy = false;
15
  let pdfText = ""; let pdfFilename = "";
16
 
17
+ // 14 MODEL FREE
18
  const DEFAULT_OR_MODELS = [
19
  "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
20
  "baidu/cobuddy:free",
 
32
  "meta-llama/llama-3.3-70b-instruct:free"
33
  ];
34
 
35
+ // TOAST NOTIFICATION (DIJAMIN MUNCUL - MURNI VANILLA CSS)
36
  function showToast(message, isError = false) {
37
  let toast = $('orbit-toast');
38
  if (!toast) {
39
  toast = document.createElement('div');
40
  toast.id = 'orbit-toast';
41
+ // Styling murni JS biar nggak diblokir Tailwind CDN
42
+ toast.style.cssText = `
43
+ position: fixed; top: 24px; left: 50%; transform: translate(-50%, -20px);
44
+ padding: 12px 24px; border-radius: 50px; box-shadow: 0 10px 25px rgba(0,0,0,0.2);
45
+ font-size: 14px; font-weight: 600; color: white; z-index: 99999;
46
+ opacity: 0; transition: all 0.3s ease-in-out; display: flex; align-items: center; gap: 8px;
47
+ pointer-events: none;
48
+ `;
49
  document.body.appendChild(toast);
50
  }
51
+
52
+ toast.style.backgroundColor = isError ? '#ef4444' : '#10b981'; // Merah / Hijau
53
+ toast.innerHTML = isError ? `<span>❌</span> <span>${message}</span>` : `<span>✅</span> <span>${message}</span>`;
54
+
55
+ // Animasi Masuk
56
+ setTimeout(() => {
57
+ toast.style.opacity = '1';
58
+ toast.style.transform = 'translate(-50%, 0)';
59
+ }, 10);
60
+
61
+ // Animasi Keluar
62
+ setTimeout(() => {
63
+ toast.style.opacity = '0';
64
+ toast.style.transform = 'translate(-50%, -20px)';
65
+ }, 3000);
66
  }
67
 
68
  // 1. DATA RECOVERY
 
95
  }
96
  });
97
 
98
+ // 3. BOOT & INIT (CACHE BUSTER AKTIF)
99
  async function init() {
100
  try {
 
101
  const me = await fetch('/api/me', { cache: 'no-store' });
102
  if(me.status === 401) { window.location.href = '/login'; return; }
103
  if(me.ok) {
 
115
  appSettings.models_agentrouter = safeArr(appSettings.models_agentrouter);
116
  appSettings.models_openai = safeArr(appSettings.models_openai);
117
 
118
+ if (!localStorage.getItem('orbit_force_free_v5')) {
 
119
  appSettings.models_openrouter = [...DEFAULT_OR_MODELS];
120
+ localStorage.setItem('orbit_force_free_v5', 'true');
121
 
 
122
  fetch('/api/settings', {
123
  method: 'POST',
124
  headers: {'Content-Type': 'application/json'},
 
312
  bindAdd('btn-add-ar', 'inp-ar', 'models_agentrouter');
313
  bindAdd('btn-add-oai', 'inp-oai', 'models_openai');
314
 
315
+ // MANTAP: ANIMASI BUTTON SAVE + TOAST IJO + AUTO CLOSE
316
  addEvt('btn-save-settings', async () => {
317
  const btn = $('btn-save-settings');
318
  const originalText = btn.textContent;
319
+
320
+ // Ubah tombol jadi "Saving..." plus spinner bulet
321
+ btn.innerHTML = `<svg class="w-4 h-4 animate-spin inline mr-2" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"></path></svg>Saving...`;
322
  btn.disabled = true;
323
 
324
  const payload = {
 
332
  models_openai: safeArr(appSettings.models_openai),
333
  current_model: $('model-select').value
334
  };
335
+
336
  try {
337
  const res = await fetch('/api/settings', {
338
  method: 'POST',
339
  headers: {'Content-Type': 'application/json'},
340
  body: JSON.stringify(payload)
341
  });
342
+
343
  if(res.ok) {
344
  appSettings = await res.json();
345
  populateModelSelect();
346
+
347
+ // Kasih delay dikit biar kerasa "kerja", terus tutup & munculin Notif
348
+ setTimeout(() => {
349
+ $('settings-modal').classList.add('hidden');
350
+ showToast("Settings saved successfully!");
351
+ }, 300);
352
+
353
  } else {
354
+ throw new Error("Gagal terhubung ke database server");
355
  }
356
  } catch(e) {
357
  console.error(e);
358
  showToast(`Error: ${e.message}`, true);
359
  } finally {
360
+ setTimeout(() => {
361
+ btn.textContent = originalText;
362
+ btn.disabled = false;
363
+ }, 300);
364
  }
365
  });
366