b08x commited on
Commit
35f3ceb
·
verified ·
1 Parent(s): f451940

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +603 -19
index.html CHANGED
@@ -1,19 +1,603 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Syncopated Dashboard</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link
9
+ rel="stylesheet"
10
+ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
11
+ />
12
+ <script>
13
+ tailwind.config = {
14
+ theme: {
15
+ extend: {
16
+ colors: {
17
+ rustic: {
18
+ 900: '#1c1917', // Very dark warm background
19
+ 800: '#292524', // Card background
20
+ 700: '#44403c', // Borders
21
+ 600: '#57534e', // Hover states
22
+ 500: '#78716c', // Muted text
23
+ },
24
+ rust: {
25
+ DEFAULT: '#c2410c', // Primary Rust
26
+ light: '#ea580c',
27
+ dim: 'rgba(194, 65, 12, 0.2)',
28
+ }
29
+ },
30
+ fontFamily: {
31
+ sans: ['Inter', 'sans-serif'],
32
+ }
33
+ }
34
+ }
35
+ }
36
+ </script>
37
+ <style>
38
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap');
39
+
40
+ body {
41
+ background-color: #1c1917;
42
+ color: #e7e5e4;
43
+ font-family: 'Inter', sans-serif;
44
+ }
45
+
46
+ /* Custom Scrollbar */
47
+ ::-webkit-scrollbar {
48
+ width: 8px;
49
+ height: 8px;
50
+ }
51
+ ::-webkit-scrollbar-track {
52
+ background: #1c1917;
53
+ }
54
+ ::-webkit-scrollbar-thumb {
55
+ background: #44403c;
56
+ border-radius: 4px;
57
+ }
58
+ ::-webkit-scrollbar-thumb:hover {
59
+ background: #c2410c;
60
+ }
61
+
62
+ /* Chatbot Popup Animations */
63
+ .chatbot-toggle {
64
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
65
+ }
66
+
67
+ .chatbot-panel {
68
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
69
+ transform-origin: bottom right;
70
+ }
71
+
72
+ .chatbot-panel.closed {
73
+ opacity: 0;
74
+ transform: scale(0.95) translateY(20px);
75
+ pointer-events: none;
76
+ }
77
+
78
+ /* Link Cards Hover Effects */
79
+ .link-card {
80
+ transition: all 0.2s ease;
81
+ border-left: 3px solid transparent;
82
+ }
83
+ .link-card:hover {
84
+ background-color: #292524;
85
+ border-left: 3px solid #c2410c;
86
+ transform: translateX(4px);
87
+ }
88
+
89
+ /* Input Focus Styles */
90
+ input:focus, select:focus {
91
+ outline: none;
92
+ border-color: #c2410c;
93
+ box-shadow: 0 0 0 2px rgba(194, 65, 12, 0.2);
94
+ }
95
+
96
+ .nav-item.active {
97
+ background-color: rgba(194, 65, 12, 0.1);
98
+ color: #c2410c;
99
+ border-right: 3px solid #c2410c;
100
+ }
101
+
102
+ .iframe-container {
103
+ background: #000;
104
+ border-radius: 0.5rem;
105
+ overflow: hidden;
106
+ }
107
+ </style>
108
+ </head>
109
+ <body class="h-screen flex flex-col overflow-hidden">
110
+
111
+ <!-- Header -->
112
+ <header class="h-16 bg-rustic-800 border-b border-rustic-700 flex items-center justify-between px-6 shrink-0 z-20">
113
+ <div class="flex items-center space-x-4">
114
+ <div class="w-8 h-8 rounded bg-rust flex items-center justify-center shadow-lg shadow-rust/20">
115
+ <i class="fas fa-cube text-white text-sm"></i>
116
+ </div>
117
+ <h1 class="text-xl font-semibold tracking-wide text-gray-100">SYNCOPATED</h1>
118
+ </div>
119
+
120
+ <div class="flex-1 max-w-2xl mx-8 hidden md:block">
121
+ <div class="flex space-x-2">
122
+ <form id="meta-search-form" class="relative flex-1">
123
+ <input
124
+ type="text"
125
+ id="search-input"
126
+ name="q"
127
+ placeholder="Search Global..."
128
+ class="w-full bg-rustic-900 border border-rustic-700 rounded-md py-1.5 px-4 pl-9 text-sm text-gray-300 focus:outline-none focus:border-rust transition"
129
+ />
130
+ <button type="submit" class="absolute left-3 top-2 text-rustic-500">
131
+ <i class="fas fa-globe text-xs"></i>
132
+ </button>
133
+ </form>
134
+ <form id="rubygems-search-form" class="relative w-64 hidden lg:block">
135
+ <input
136
+ type="text"
137
+ id="rubygems-search-input"
138
+ name="q"
139
+ placeholder="RubyGems..."
140
+ class="w-full bg-rustic-900 border border-rustic-700 rounded-md py-1.5 px-4 pl-9 text-sm text-gray-300 focus:outline-none focus:border-rust transition"
141
+ />
142
+ <button type="submit" class="absolute left-3 top-2 text-rustic-500">
143
+ <i class="fas fa-gem text-xs text-rust-light"></i>
144
+ </button>
145
+ </form>
146
+ </div>
147
+ </div>
148
+
149
+ <div class="flex items-center space-x-4">
150
+ <button class="text-gray-400 hover:text-rust-light transition">
151
+ <i class="fas fa-bell"></i>
152
+ </button>
153
+ <div class="w-8 h-8 rounded-full bg-rustic-700 flex items-center justify-center cursor-pointer border border-rustic-600">
154
+ <i class="fas fa-user text-gray-400 text-xs"></i>
155
+ </div>
156
+ </div>
157
+ </header>
158
+
159
+ <!-- Main Layout -->
160
+ <div class="flex flex-1 overflow-hidden">
161
+
162
+ <!-- Left Column: Link Modals (Prominently Featured) -->
163
+ <aside class="w-80 bg-rustic-900 border-r border-rustic-700 flex flex-col overflow-y-auto shrink-0 hidden md:flex">
164
+ <div class="p-4">
165
+ <h2 class="text-xs font-bold text-rustic-500 uppercase tracking-wider mb-4 pl-2">Launcher</h2>
166
+
167
+ <!-- Dashboard View (Link Categories) -->
168
+ <div id="dashboard-links-view" class="space-y-6">
169
+ <!-- Links will be injected here via JS -->
170
+ </div>
171
+ </div>
172
+
173
+ <!-- Secondary Nav for other tabs -->
174
+ <div class="mt-auto p-4 border-t border-rustic-700">
175
+ <nav class="space-y-1">
176
+ <button class="nav-item w-full text-left px-3 py-2 rounded-md text-sm font-medium flex items-center space-x-3 text-gray-400 hover:bg-rustic-800" data-tab="documents">
177
+ <i class="fas fa-file-alt w-4"></i>
178
+ <span>Documents</span>
179
+ </button>
180
+ <button class="nav-item w-full text-left px-3 py-2 rounded-md text-sm font-medium flex items-center space-x-3 text-gray-400 hover:bg-rustic-800" data-tab="generate">
181
+ <i class="fas fa-code w-4"></i>
182
+ <span>Generate</span>
183
+ </button>
184
+ <button class="nav-item w-full text-left px-3 py-2 rounded-md text-sm font-medium flex items-center space-x-3 text-gray-400 hover:bg-rustic-800" data-tab="settings">
185
+ <i class="fas fa-cog w-4"></i>
186
+ <span>Settings</span>
187
+ </button>
188
+ </nav>
189
+ </div>
190
+ </aside>
191
+
192
+ <!-- Right Column: Main Content Area -->
193
+ <main class="flex-1 bg-rustic-900 overflow-y-auto relative p-6" id="main-content-area">
194
+
195
+ <!-- Tab Content: Documents -->
196
+ <div id="documents" class="tab-content hidden">
197
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
198
+ <div class="bg-rustic-800 rounded-xl p-1 border border-rustic-700 shadow-lg">
199
+ <div class="bg-rustic-900 rounded-t-lg px-4 py-3 border-b border-rustic-700 flex justify-between items-center">
200
+ <span class="text-sm font-medium text-gray-300">Document Management</span>
201
+ <i class="fas fa-external-link-alt text-xs text-gray-500"></i>
202
+ </div>
203
+ <div class="h-64 iframe-container">
204
+ <iframe src="https://docs.example.com/browse" class="w-full h-full" allowfullscreen></iframe>
205
+ </div>
206
+ </div>
207
+
208
+ <div class="bg-rustic-800 rounded-xl p-1 border border-rustic-700 shadow-lg">
209
+ <div class="bg-rustic-900 rounded-t-lg px-4 py-3 border-b border-rustic-700 flex justify-between items-center">
210
+ <span class="text-sm font-medium text-gray-300">Knowledge Base</span>
211
+ <i class="fas fa-external-link-alt text-xs text-gray-500"></i>
212
+ </div>
213
+ <div class="h-64 iframe-container">
214
+ <iframe src="https://wiki.example.com/home" class="w-full h-full" allowfullscreen></iframe>
215
+ </div>
216
+ </div>
217
+ </div>
218
+ </div>
219
+
220
+ <!-- Tab Content: Generate -->
221
+ <div id="generate" class="tab-content hidden">
222
+ <div class="grid grid-cols-1 gap-6">
223
+ <div class="bg-rustic-800 rounded-xl p-1 border border-rustic-700 shadow-lg">
224
+ <div class="bg-rustic-900 rounded-t-lg px-4 py-3 border-b border-rustic-700 flex justify-between items-center">
225
+ <span class="text-sm font-medium text-gray-300">Code Generator</span>
226
+ <i class="fas fa-robot text-rust"></i>
227
+ </div>
228
+ <div class="h-96 iframe-container">
229
+ <iframe src="https://directory.example.com" class="w-full h-full" allowfullscreen></iframe>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ </div>
234
+
235
+ <!-- Tab Content: Settings -->
236
+ <div id="settings" class="tab-content hidden">
237
+ <div class="max-w-2xl">
238
+ <div class="bg-rustic-800 rounded-xl p-6 border border-rustic-700">
239
+ <h3 class="text-lg font-medium text-white mb-6">Data Management</h3>
240
+ <div class="flex items-center space-x-4">
241
+ <button id="exportLinksBtn" class="bg-rust hover:bg-rust-light text-white font-medium py-2 px-4 rounded-lg flex items-center space-x-2 transition shadow-lg shadow-rust/20">
242
+ <i class="fas fa-file-export"></i>
243
+ <span>Export Config</span>
244
+ </button>
245
+ <button id="importLinksBtn" class="bg-rustic-700 hover:bg-rustic-600 text-white font-medium py-2 px-4 rounded-lg flex items-center space-x-2 transition">
246
+ <i class="fas fa-file-import"></i>
247
+ <span>Import Config</span>
248
+ </button>
249
+ <input type="file" id="importFileInput" class="hidden" accept=".json" />
250
+ </div>
251
+ <p class="text-sm text-rustic-500 mt-4">
252
+ Manage your sidebar link configuration here.
253
+ </p>
254
+ </div>
255
+ </div>
256
+ </div>
257
+
258
+ <!-- Default View (Welcome / Empty state if needed, but links are in sidebar now) -->
259
+ <div id="dashboard" class="tab-content block h-full flex items-center justify-center text-rustic-500 flex-col">
260
+ <div class="text-center">
261
+ <i class="fas fa-compass text-4xl mb-4 text-rustic-700"></i>
262
+ <p>Select a category from the launcher to get started.</p>
263
+ </div>
264
+ </div>
265
+
266
+ </main>
267
+ </div>
268
+
269
+ <!-- Chatbot Popup (Refactored Main View) -->
270
+ <div class="fixed bottom-6 right-6 z-50 flex flex-col items-end">
271
+ <!-- Chat Panel -->
272
+ <div id="chatbot-panel" class="chatbot-panel closed bg-rustic-800 rounded-xl shadow-2xl border border-rustic-700 w-[380px] h-[500px] mb-4 flex flex-col overflow-hidden">
273
+ <div class="bg-rust p-3 flex justify-between items-center shrink-0">
274
+ <div class="flex items-center space-x-2">
275
+ <div class="w-2 h-2 bg-white rounded-full animate-pulse"></div>
276
+ <span class="font-medium text-white text-sm">Assistant</span>
277
+ </div>
278
+ <button id="closeChatBtn" class="text-white hover:text-gray-200">
279
+ <i class="fas fa-times"></i>
280
+ </button>
281
+ </div>
282
+ <div class="flex-1 bg-black relative">
283
+ <iframe
284
+ src="http://ninjabot/chatbot/YuXRYou2mbnDqCXc"
285
+ class="w-full h-full"
286
+ frameborder="0"
287
+ allow="microphone">
288
+ </iframe>
289
+ </div>
290
+ </div>
291
+
292
+ <!-- Toggle Button -->
293
+ <button id="chatbot-toggle-btn" class="chatbot-toggle w-14 h-14 bg-rust hover:bg-rust-light rounded-full shadow-lg shadow-rust/40 flex items-center justify-center text-white transform hover:scale-110">
294
+ <i class="fas fa-comment-dots text-xl"></i>
295
+ </button>
296
+ </div>
297
+
298
+ <!-- Link Settings Modal -->
299
+ <div id="linkSettingsModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm flex items-center justify-center hidden z-[60]">
300
+ <div class="bg-rustic-800 border border-rustic-700 rounded-lg p-6 w-full max-w-md shadow-2xl">
301
+ <div class="flex justify-between items-center mb-6">
302
+ <h3 class="text-xl font-semibold text-white">Edit Launcher</h3>
303
+ <button id="modalCloseBtn" class="text-gray-400 hover:text-white transition">
304
+ <i class="fas fa-times"></i>
305
+ </button>
306
+ </div>
307
+ <div class="space-y-4">
308
+ <div>
309
+ <label class="block text-sm font-medium text-gray-400 mb-1">Category Title</label>
310
+ <input type="text" id="categoryName" class="w-full bg-rustic-900 border border-rustic-700 rounded px-3 py-2 text-white" />
311
+ </div>
312
+ <div>
313
+ <label class="block text-sm font-medium text-gray-400 mb-2">Links</label>
314
+ <div id="linkItems" class="space-y-3 max-h-64 overflow-y-auto pr-2">
315
+ <!-- Links injected here -->
316
+ </div>
317
+ <button id="addNewLinkBtn" class="mt-3 text-rust text-sm flex items-center space-x-1 hover:text-rust-light transition">
318
+ <i class="fas fa-plus"></i>
319
+ <span>Add New Link</span>
320
+ </button>
321
+ </div>
322
+ </div>
323
+ <div class="flex justify-end space-x-3 mt-8">
324
+ <button id="modalCancelBtn" class="px-4 py-2 rounded-md bg-rustic-900 hover:bg-rustic-700 text-gray-300 transition border border-rustic-700">
325
+ Cancel
326
+ </button>
327
+ <button id="saveChangesBtn" class="px-4 py-2 rounded-md bg-rust hover:bg-rust-light text-white transition shadow-lg shadow-rust/20">
328
+ Save Changes
329
+ </button>
330
+ </div>
331
+ </div>
332
+ </div>
333
+
334
+ <script>
335
+ document.addEventListener("DOMContentLoaded", () => {
336
+ // --- State ---
337
+ let currentCategory = "";
338
+ const storageKey = "dashboardLinks";
339
+
340
+ const iconClasses = {
341
+ blue: "fa-tachometer-alt text-blue-400",
342
+ green: "fa-project-diagram text-green-400",
343
+ purple: "fa-comments text-purple-400",
344
+ yellow: "fa-calendar text-yellow-400",
345
+ red: "fa-book text-red-400",
346
+ teal: "fa-users text-teal-400",
347
+ rust: "fa-link text-rust-light",
348
+ gray: "fa-anchor text-gray-400"
349
+ };
350
+
351
+ const defaultLinks = {
352
+ quick: {
353
+ title: "Quick Access",
354
+ links: [
355
+ { name: "Analytics Dashboard", url: "#", color: "blue" },
356
+ { name: "Project Tracker", url: "#", color: "green" },
357
+ { name: "Team Chat", url: "#", color: "purple" },
358
+ ],
359
+ },
360
+ resources: {
361
+ title: "Company Hub",
362
+ links: [
363
+ { name: "Company Calendar", url: "#", color: "yellow" },
364
+ { name: "Employee Handbook", url: "#", color: "red" },
365
+ { name: "Org Directory", url: "#", color: "teal" },
366
+ ],
367
+ },
368
+ support: {
369
+ title: "Support Zone",
370
+ links: [
371
+ { name: "Submit Ticket", url: "#", color: "rust" },
372
+ { name: "Help Center", url: "#", color: "gray" },
373
+ ],
374
+ }
375
+ };
376
+
377
+ // --- Functions ---
378
+ const getStoredLinks = () => {
379
+ const links = localStorage.getItem(storageKey);
380
+ return links ? JSON.parse(links) : defaultLinks;
381
+ };
382
+
383
+ const saveLinksToStorage = (links) => {
384
+ localStorage.setItem(storageKey, JSON.stringify(links));
385
+ };
386
+
387
+ const renderSidebarLinks = () => {
388
+ const container = document.getElementById("dashboard-links-view");
389
+ const allLinks = getStoredLinks();
390
+
391
+ container.innerHTML = "";
392
+
393
+ Object.keys(allLinks).forEach((category) => {
394
+ const data = allLinks[category];
395
+
396
+ const section = document.createElement("div");
397
+ section.className = "mb-2";
398
+
399
+ // Header with Edit Button
400
+ const header = document.createElement("div");
401
+ header.className = "flex justify-between items-center mb-2 px-2";
402
+ header.innerHTML = `
403
+ <h3 class="font-semibold text-gray-200 text-sm uppercase tracking-wide">${data.title}</h3>
404
+ <button class="text-rustic-500 hover:text-rust transition text-xs" data-category="${category}">
405
+ <i class="fas fa-cog"></i>
406
+ </button>
407
+ `;
408
+
409
+ // Links List
410
+ const list = document.createElement("div");
411
+ list.className = "space-y-1";
412
+
413
+ data.links.forEach(link => {
414
+ const icon = iconClasses[link.color] || "fa-link text-gray-400";
415
+ const a = document.createElement("a");
416
+ a.href = link.url;
417
+ a.target = "_blank";
418
+ a.className = "link-card flex items-center space-x-3 py-2 px-3 rounded-md text-gray-400 hover:text-white cursor-pointer";
419
+ a.innerHTML = `
420
+ <i class="fas ${icon} w-4 text-center"></i>
421
+ <span class="text-sm truncate">${link.name}</span>
422
+ `;
423
+ list.appendChild(a);
424
+ });
425
+
426
+ section.appendChild(header);
427
+ section.appendChild(list);
428
+ container.appendChild(section);
429
+ });
430
+
431
+ // Re-attach event listeners for edit buttons
432
+ document.querySelectorAll("#dashboard-links-view button[data-category]").forEach(btn => {
433
+ btn.addEventListener("click", (e) => showLinkSettings(e.currentTarget.dataset.category));
434
+ });
435
+ };
436
+
437
+ const hideLinkSettings = () => document.getElementById("linkSettingsModal").classList.add("hidden");
438
+
439
+ const addNewLink = (name = "", url = "", color = "rust") => {
440
+ const linkItems = document.getElementById("linkItems");
441
+ const newLink = document.createElement("div");
442
+ newLink.className = "flex items-center space-x-2 link-item-entry";
443
+
444
+ let optionsHtml = Object.keys(iconClasses)
445
+ .map((key) => `<option value="${key}" ${key === color ? "selected" : ""}>${key.charAt(0).toUpperCase() + key.slice(1)}</option>`)
446
+ .join("");
447
+
448
+ newLink.innerHTML = `
449
+ <input type="text" placeholder="Name" class="flex-1 bg-rustic-900 border border-rustic-700 rounded px-2 py-1.5 text-white text-sm" value="${name}">
450
+ <input type="text" placeholder="URL" class="flex-1 bg-rustic-900 border border-rustic-700 rounded px-2 py-1.5 text-white text-sm" value="${url}">
451
+ <select class="bg-rustic-900 border border-rustic-700 rounded px-1 py-1.5 text-white text-sm">${optionsHtml}</select>
452
+ <button class="text-red-500 hover:text-red-400 p-1.5 remove-link-btn"><i class="fas fa-trash"></i></button>
453
+ `;
454
+ linkItems.appendChild(newLink);
455
+ };
456
+
457
+ const showLinkSettings = (category) => {
458
+ currentCategory = category;
459
+ const allLinks = getStoredLinks();
460
+ const data = allLinks[currentCategory];
461
+
462
+ document.getElementById("categoryName").value = data.title;
463
+ const linkItemsContainer = document.getElementById("linkItems");
464
+ linkItemsContainer.innerHTML = "";
465
+
466
+ if (data.links) {
467
+ data.links.forEach(link => addNewLink(link.name, link.url, link.color));
468
+ }
469
+
470
+ document.getElementById("linkSettingsModal").classList.remove("hidden");
471
+ };
472
+
473
+ const saveLinkSettings = () => {
474
+ const newTitle = document.getElementById("categoryName").value;
475
+ const linkItems = document.querySelectorAll("#linkItems .link-item-entry");
476
+ const newLinks = Array.from(linkItems)
477
+ .map((item) => ({
478
+ name: item.children[0].value,
479
+ url: item.children[1].value,
480
+ color: item.children[2].value,
481
+ }))
482
+ .filter((link) => link.name && link.url);
483
+
484
+ const allLinks = getStoredLinks();
485
+ allLinks[currentCategory] = { title: newTitle, links: newLinks };
486
+
487
+ saveLinksToStorage(allLinks);
488
+ renderSidebarLinks();
489
+ hideLinkSettings();
490
+ };
491
+
492
+ // --- Chatbot Logic ---
493
+ const chatPanel = document.getElementById('chatbot-panel');
494
+ const chatBtn = document.getElementById('chatbot-toggle-btn');
495
+ const closeChatBtn = document.getElementById('closeChatBtn');
496
+ let isChatOpen = false;
497
+
498
+ const toggleChat = () => {
499
+ isChatOpen = !isChatOpen;
500
+ if(isChatOpen) {
501
+ chatPanel.classList.remove('closed');
502
+ chatBtn.classList.add('hidden');
503
+ } else {
504
+ chatPanel.classList.add('closed');
505
+ setTimeout(() => {
506
+ if(!isChatOpen) chatBtn.classList.remove('hidden');
507
+ }, 300);
508
+ }
509
+ };
510
+
511
+ chatBtn.addEventListener('click', toggleChat);
512
+ closeChatBtn.addEventListener('click', toggleChat);
513
+
514
+ // --- Tab Logic ---
515
+ const switchTab = (event) => {
516
+ const tabId = event.currentTarget.dataset.tab;
517
+
518
+ // Hide all tab contents
519
+ document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));
520
+ document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('block'));
521
+
522
+ // Show target
523
+ const target = document.getElementById(tabId);
524
+ if(target) {
525
+ target.classList.remove('hidden');
526
+ target.classList.add('block');
527
+ }
528
+
529
+ // Update nav state (if it's a side nav item)
530
+ document.querySelectorAll('.nav-item').forEach(el => el.classList.remove('active'));
531
+ event.currentTarget.classList.add('active');
532
+ };
533
+
534
+ // --- Search Handlers ---
535
+ const handleMetaSearch = (e) => {
536
+ e.preventDefault();
537
+ const q = document.getElementById('search-input').value;
538
+ if(q) window.open(`https://www.google.com/search?q=${encodeURIComponent(q)}`, '_blank');
539
+ };
540
+
541
+ const handleRubyGemsSearch = (e) => {
542
+ e.preventDefault();
543
+ const q = document.getElementById('rubygems-search-input').value;
544
+ if(q) window.open(`https://rubygems.org/search?query=${encodeURIComponent(q)}`, '_blank');
545
+ };
546
+
547
+ // --- Import/Export ---
548
+ const handleExport = () => {
549
+ const data = localStorage.getItem(storageKey);
550
+ if(!data) return;
551
+ const a = document.createElement('a');
552
+ a.href = URL.createObjectURL(new Blob([data], {type: 'application/json'}));
553
+ a.download = 'links.json';
554
+ a.click();
555
+ };
556
+
557
+ const handleImport = (e) => {
558
+ const file = e.target.files[0];
559
+ if(!file) return;
560
+ const r = new FileReader();
561
+ r.onload = (ev) => {
562
+ try {
563
+ const data = JSON.parse(ev.target.result);
564
+ localStorage.setItem(storageKey, JSON.stringify(data));
565
+ renderSidebarLinks();
566
+ alert("Imported successfully");
567
+ } catch(err) { alert("Invalid file"); }
568
+ };
569
+ r.readAsText(file);
570
+ e.target.value = '';
571
+ };
572
+
573
+ // --- Init ---
574
+ renderSidebarLinks();
575
+
576
+ // Listeners
577
+ document.getElementById('meta-search-form').addEventListener('submit', handleMetaSearch);
578
+ document.getElementById('rubygems-search-form').addEventListener('submit', handleRubyGemsSearch);
579
+
580
+ // Sidebar Navigation
581
+ document.querySelectorAll('.nav-item').forEach(item => {
582
+ item.addEventListener('click', switchTab);
583
+ });
584
+
585
+ // Modal
586
+ document.getElementById('modalCloseBtn').addEventListener('click', hideLinkSettings);
587
+ document.getElementById('modalCancelBtn').addEventListener('click', hideLinkSettings);
588
+ document.getElementById('saveChangesBtn').addEventListener('click', saveLinkSettings);
589
+ document.getElementById('addNewLinkBtn').addEventListener('click', () => addNewLink());
590
+
591
+ document.getElementById('linkItems').addEventListener('click', (e) => {
592
+ if(e.target.closest('.remove-link-btn')) e.target.closest('.link-item-entry').remove();
593
+ });
594
+
595
+ // Import/Export
596
+ document.getElementById('exportLinksBtn').addEventListener('click', handleExport);
597
+ document.getElementById('importLinksBtn').addEventListener('click', () => document.getElementById('importFileInput').click());
598
+ document.getElementById('importFileInput').addEventListener('change', handleImport);
599
+
600
+ });
601
+ </script>
602
+ </body>
603
+ </html>