rockson8 commited on
Commit
7a0ec44
·
verified ·
1 Parent(s): 6e5cc99

teraz nie widzę nic przy samej górze pasku, nawet ikony ustawien - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +579 -18
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Localllm
3
- emoji: 🔥
4
  colorFrom: yellow
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: localllm
3
+ emoji: 🐳
4
  colorFrom: yellow
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,580 @@
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>Local LLM Chat</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ <style>
11
+ :root {
12
+ --primary: #6366f1;
13
+ --primary-dark: #4f46e5;
14
+ --bg: #0f172a;
15
+ --text: #e2e8f0;
16
+ --text-light: #94a3b8;
17
+ --border: #1e293b;
18
+ }
19
+
20
+ .dark {
21
+ --bg: #0f172a;
22
+ --text: #e2e8f0;
23
+ --text-light: #94a3b8;
24
+ --border: #1e293b;
25
+ }
26
+
27
+ .light {
28
+ --bg: #f9fafb;
29
+ --text: #111827;
30
+ --text-light: #6b7280;
31
+ --border: #e5e7eb;
32
+ }
33
+
34
+ body {
35
+ width: 400px;
36
+ height: 600px;
37
+ font-family: 'Inter', sans-serif;
38
+ background-color: var(--bg);
39
+ color: var(--text);
40
+ transition: background-color 0.3s, color 0.3s;
41
+ }
42
+
43
+ .chat-container {
44
+ height: calc(100% - 60px);
45
+ }
46
+
47
+ .message-user {
48
+ background-color: var(--primary);
49
+ color: white;
50
+ border-radius: 12px 12px 0 12px;
51
+ }
52
+
53
+ .message-ai {
54
+ background-color: #1e293b;
55
+ border: 1px solid var(--border);
56
+ border-radius: 12px 12px 12px 0;
57
+ }
58
+
59
+ .rounded-12px {
60
+ border-radius: 12px !important;
61
+ }
62
+
63
+ .rounded-none {
64
+ border-radius: 0 !important;
65
+ }
66
+
67
+ .rounded-full {
68
+ border-radius: 9999px !important;
69
+ }
70
+
71
+ .typing-indicator span {
72
+ display: inline-block;
73
+ width: 8px;
74
+ height: 8px;
75
+ background-color: var(--primary);
76
+ border-radius: 50%;
77
+ margin: 0 2px;
78
+ opacity: 0.4;
79
+ }
80
+
81
+ .typing-indicator span:nth-child(1) {
82
+ animation: pulse 1s infinite;
83
+ }
84
+
85
+ .typing-indicator span:nth-child(2) {
86
+ animation: pulse 1s infinite 0.2s;
87
+ }
88
+
89
+ .typing-indicator span:nth-child(3) {
90
+ animation: pulse 1s infinite 0.4s;
91
+ }
92
+
93
+ @keyframes pulse {
94
+ 0%, 100% {
95
+ opacity: 0.4;
96
+ transform: scale(1);
97
+ }
98
+ 50% {
99
+ opacity: 1;
100
+ transform: scale(1.2);
101
+ }
102
+ }
103
+
104
+ .input-box {
105
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
106
+ background-color: #1e293b;
107
+ }
108
+
109
+ .header-dark {
110
+ background-color: #1e293b;
111
+ border-color: #334155;
112
+ }
113
+
114
+ .modal-dark {
115
+ background-color: #1e293b;
116
+ color: #e2e8f0;
117
+ }
118
+
119
+ .modal-dark input,
120
+ .modal-dark select {
121
+ background-color: #334155;
122
+ color: #e2e8f0;
123
+ border-color: #475569;
124
+ }
125
+
126
+ .modal-dark .border-gray-200 {
127
+ border-color: #334155;
128
+ }
129
+ </style>
130
+ </head>
131
+ <body class="flex flex-col">
132
+ <header class="header-dark px-4 py-3 border-b border-gray-800 flex items-center justify-between sticky top-0 z-10">
133
+ <div class="flex items-center space-x-2">
134
+ <div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center">
135
+ <i data-feather="cpu" class="text-indigo-500 w-4 h-4"></i>
136
+ </div>
137
+ <h1 class="font-semibold text-white">Local LLM</h1>
138
+ </div>
139
+ <div class="flex items-center space-x-2">
140
+ <button id="settings-btn" class="p-1 rounded-full hover:bg-gray-700">
141
+ <i data-feather="settings" class="w-5 h-5 text-white"></i>
142
+ </button>
143
+ <button id="clear-btn" class="p-1 rounded-full hover:bg-gray-700">
144
+ <i data-feather="trash-2" class="w-5 h-5 text-white"></i>
145
+ </button>
146
+ </div>
147
+ </header>
148
+
149
+ <div class="chat-container overflow-y-auto flex-1 px-4 py-3 space-y-3" id="chat-messages">
150
+ <div class="message-ai p-3 max-w-[80%]">
151
+ <p class="text-sm">Hello! I'm your local AI assistant. How can I help you today?</p>
152
+ </div>
153
+ </div>
154
+
155
+ <div class="input-box bg-white px-4 py-3 border-t border-gray-200 sticky bottom-0">
156
+ <div class="flex items-center space-x-2">
157
+ <input
158
+ type="text"
159
+ id="message-input"
160
+ placeholder="Type your message..."
161
+ class="flex-1 border border-gray-300 rounded-full px-4 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm bg-white text-gray-900"
162
+ autocomplete="off"
163
+ >
164
+ <button id="send-btn" class="bg-indigo-500 hover:bg-indigo-600 text-white rounded-full p-2 transition-colors">
165
+ <i data-feather="send" class="w-4 h-4"></i>
166
+ </button>
167
+ </div>
168
+ <div class="flex items-center justify-between mt-2 text-xs text-gray-500">
169
+ <div class="flex items-center space-x-2">
170
+ <button id="model-selector" class="flex items-center space-x-1 hover:text-indigo-500">
171
+ <span>Ollama</span>
172
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
173
+ </button>
174
+ </div>
175
+ <div class="flex items-center space-x-2">
176
+ <button id="api-settings" class="hover:text-indigo-500 flex items-center">
177
+ <i data-feather="link" class="w-3 h-3 mr-1"></i>
178
+ <span>API Settings</span>
179
+ </button>
180
+ </div>
181
+ </div>
182
+ </div>
183
+
184
+ <!-- Settings Modal -->
185
+ <div id="settings-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden">
186
+ <div class="modal-dark bg-gray-900 rounded-lg w-full max-w-md mx-4">
187
+ <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
188
+ <h3 class="text-lg font-medium text-gray-900">Settings</h3>
189
+ <button id="close-settings" class="text-gray-400 hover:text-gray-500">
190
+ <i data-feather="x" class="w-5 h-5"></i>
191
+ </button>
192
+ </div>
193
+ <div class="px-6 py-4 space-y-4">
194
+ <div>
195
+ <label class="block text-sm font-medium text-gray-700 mb-1">AI Role</label>
196
+ <textarea id="ai-role" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm" placeholder="You are a helpful AI assistant..."></textarea>
197
+ </div>
198
+ <div>
199
+ <label class="block text-sm font-medium text-gray-700 mb-1">Prompt Library</label>
200
+ <select id="prompt-library" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm">
201
+ <option value="">Select a prompt...</option>
202
+ <option value="creative">Creative Writer</option>
203
+ <option value="coder">Code Assistant</option>
204
+ <option value="analyst">Data Analyst</option>
205
+ <option value="tutor">Learning Tutor</option>
206
+ </select>
207
+ </div>
208
+ <div>
209
+ <label class="block text-sm font-medium text-gray-700 mb-1">Ollama API URL</label>
210
+ <input type="text" id="api-url" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm" placeholder="http://localhost:11434">
211
+ </div>
212
+ <div>
213
+ <label class="block text-sm font-medium text-gray-700 mb-1">Default Model</label>
214
+ <select id="default-model" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm">
215
+ <option value="llama2">Llama 2</option>
216
+ <option value="mistral">Mistral</option>
217
+ <option value="gemma">Gemma</option>
218
+ <option value="phi">Phi</option>
219
+ </select>
220
+ </div>
221
+ <div>
222
+ <label class="block text-sm font-medium text-gray-700 mb-1">Theme</label>
223
+ <select id="theme-selector" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm">
224
+ <option value="light">Light</option>
225
+ <option value="dark">Dark</option>
226
+ <option value="system">System</option>
227
+ </select>
228
+ </div>
229
+ <div>
230
+ <label class="block text-sm font-medium text-gray-700 mb-1">Message Style</label>
231
+ <select id="message-style" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm">
232
+ <option value="rounded">Rounded</option>
233
+ <option value="square">Square</option>
234
+ <option value="bubble">Bubble</option>
235
+ </select>
236
+ </div>
237
+ <div>
238
+ <label class="block text-sm font-medium text-gray-700 mb-1">Font Size</label>
239
+ <select id="font-size" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent text-sm">
240
+ <option value="small">Small</option>
241
+ <option value="medium">Medium</option>
242
+ <option value="large">Large</option>
243
+ </select>
244
+ </div>
245
+ <div class="flex items-center justify-between">
246
+ <label class="block text-sm font-medium text-gray-700 mb-1">Enable Markdown</label>
247
+ <label class="relative inline-flex items-center cursor-pointer">
248
+ <input type="checkbox" id="markdown-toggle" class="sr-only peer">
249
+ <div class="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-indigo-600"></div>
250
+ </label>
251
+ </div>
252
+ <div class="flex items-center justify-between">
253
+ <label class="block text-sm font-medium text-gray-700 mb-1">Enable Animations</label>
254
+ <label class="relative inline-flex items-center cursor-pointer">
255
+ <input type="checkbox" id="animations-toggle" class="sr-only peer">
256
+ <div class="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-indigo-600"></div>
257
+ </label>
258
+ </div>
259
+ </div>
260
+ <div class="px-6 py-4 border-t border-gray-200 flex justify-end">
261
+ <button id="save-settings" class="bg-indigo-500 hover:bg-indigo-600 text-white px-4 py-2 rounded-md text-sm font-medium">Save</button>
262
+ </div>
263
+ </div>
264
+ </div>
265
+
266
+ <script>
267
+ feather.replace();
268
+
269
+ // DOM Elements
270
+ const messageInput = document.getElementById('message-input');
271
+ const sendBtn = document.getElementById('send-btn');
272
+ const chatMessages = document.getElementById('chat-messages');
273
+ const settingsBtn = document.getElementById('settings-btn');
274
+ const clearBtn = document.getElementById('clear-btn');
275
+ const settingsModal = document.getElementById('settings-modal');
276
+ const closeSettings = document.getElementById('close-settings');
277
+ const saveSettings = document.getElementById('save-settings');
278
+ const apiSettings = document.getElementById('api-settings');
279
+ const modelSelector = document.getElementById('model-selector');
280
+
281
+ // Apply dark theme by default
282
+ document.documentElement.classList.add('dark');
283
+
284
+ // Load settings from storage
285
+ chrome.storage.sync.get([
286
+ 'apiUrl',
287
+ 'defaultModel',
288
+ 'theme',
289
+ 'messageStyle',
290
+ 'fontSize',
291
+ 'markdownEnabled',
292
+ 'animationsEnabled',
293
+ 'aiRole',
294
+ 'selectedPrompt'
295
+ ], (result) => {
296
+ if (result.apiUrl) document.getElementById('api-url').value = result.apiUrl;
297
+ if (result.defaultModel) document.getElementById('default-model').value = result.defaultModel;
298
+ if (result.theme) applyTheme(result.theme);
299
+ if (result.messageStyle) document.getElementById('message-style').value = result.messageStyle;
300
+ if (result.fontSize) document.getElementById('font-size').value = result.fontSize;
301
+ if (result.markdownEnabled) document.getElementById('markdown-toggle').checked = result.markdownEnabled;
302
+ if (result.animationsEnabled) document.getElementById('animations-toggle').checked = result.animationsEnabled;
303
+
304
+ applyMessageStyle(result.messageStyle || 'rounded');
305
+ applyFontSize(result.fontSize || 'medium');
306
+ });
307
+
308
+ // Event Listeners
309
+ sendBtn.addEventListener('click', sendMessage);
310
+ messageInput.addEventListener('keypress', (e) => {
311
+ if (e.key === 'Enter') {
312
+ sendMessage();
313
+ }
314
+ });
315
+
316
+ settingsBtn.addEventListener('click', () => {
317
+ settingsModal.classList.remove('hidden');
318
+ });
319
+
320
+ closeSettings.addEventListener('click', () => {
321
+ settingsModal.classList.add('hidden');
322
+ });
323
+
324
+ saveSettings.addEventListener('click', () => {
325
+ const apiUrl = document.getElementById('api-url').value;
326
+ const defaultModel = document.getElementById('default-model').value;
327
+ const theme = document.getElementById('theme-selector').value;
328
+ const messageStyle = document.getElementById('message-style').value;
329
+ const fontSize = document.getElementById('font-size').value;
330
+ const markdownEnabled = document.getElementById('markdown-toggle').checked;
331
+ const animationsEnabled = document.getElementById('animations-toggle').checked;
332
+ const aiRole = document.getElementById('ai-role').value;
333
+ const selectedPrompt = document.getElementById('prompt-library').value;
334
+
335
+ chrome.storage.sync.set({
336
+ apiUrl,
337
+ defaultModel,
338
+ theme,
339
+ messageStyle,
340
+ fontSize,
341
+ markdownEnabled,
342
+ animationsEnabled,
343
+ aiRole,
344
+ selectedPrompt
345
+ }, () => {
346
+ applyTheme(theme);
347
+ applyMessageStyle(messageStyle);
348
+ applyFontSize(fontSize);
349
+ settingsModal.classList.add('hidden');
350
+ showNotification('Settings saved successfully');
351
+ });
352
+ });
353
+
354
+ clearBtn.addEventListener('click', () => {
355
+ chatMessages.innerHTML = `
356
+ <div class="message-ai p-3 max-w-[80%]">
357
+ <p class="text-sm">Hello! I'm your local AI assistant. How can I help you today?</p>
358
+ </div>
359
+ `;
360
+ });
361
+
362
+ apiSettings.addEventListener('click', () => {
363
+ settingsModal.classList.remove('hidden');
364
+ });
365
+
366
+ // Functions
367
+ function sendMessage() {
368
+ const message = messageInput.value.trim();
369
+ if (!message) return;
370
+
371
+ // Get AI role and selected prompt
372
+ chrome.storage.sync.get(['aiRole', 'selectedPrompt'], (result) => {
373
+ let fullMessage = message;
374
+
375
+ if (result.aiRole) {
376
+ fullMessage = `${result.aiRole}\n\n${message}`;
377
+ }
378
+
379
+ if (result.selectedPrompt) {
380
+ const prompts = {
381
+ 'creative': 'You are a creative writer. Respond with imaginative and vivid descriptions.',
382
+ 'coder': 'You are a coding assistant. Respond with clean, efficient code examples.',
383
+ 'analyst': 'You are a data analyst. Respond with clear, structured analysis.',
384
+ 'tutor': 'You are a learning tutor. Explain concepts clearly with examples.'
385
+ };
386
+ fullMessage = `${prompts[result.selectedPrompt]}\n\n${fullMessage}`;
387
+ }
388
+
389
+ // Add user message to chat
390
+ addMessage(message, 'user');
391
+ messageInput.value = '';
392
+
393
+ // Show typing indicator
394
+ const typingIndicator = document.createElement('div');
395
+ typingIndicator.className = 'typing-indicator p-3 max-w-[80%]';
396
+ typingIndicator.innerHTML = `
397
+ <div class="flex space-x-1">
398
+ <span></span>
399
+ <span></span>
400
+ <span></span>
401
+ </div>
402
+ `;
403
+ chatMessages.appendChild(typingIndicator);
404
+ chatMessages.scrollTop = chatMessages.scrollHeight;
405
+
406
+ // Get API settings
407
+ chrome.storage.sync.get(['apiUrl', 'defaultModel'], async (result) => {
408
+ const apiUrl = result.apiUrl || 'http://localhost:11434';
409
+ const model = result.defaultModel || 'llama2';
410
+
411
+ try {
412
+ // Call Ollama API
413
+ const response = await fetch(`${apiUrl}/api/generate`, {
414
+ method: 'POST',
415
+ headers: {
416
+ 'Content-Type': 'application/json'
417
+ },
418
+ body: JSON.stringify({
419
+ model: model,
420
+ prompt: fullMessage,
421
+ stream: false
422
+ })
423
+ });
424
+
425
+ if (!response.ok) {
426
+ throw new Error(`API request failed: ${response.status}`);
427
+ }
428
+
429
+ const data = await response.json();
430
+
431
+ // Remove typing indicator
432
+ chatMessages.removeChild(typingIndicator);
433
+
434
+ // Add AI response to chat
435
+ addMessage(data.response, 'ai');
436
+ } catch (error) {
437
+ console.error('Error:', error);
438
+ chatMessages.removeChild(typingIndicator);
439
+ addMessage(`Error: ${error.message}`, 'ai');
440
+ }
441
+ });
442
+ }
443
+
444
+ function addMessage(text, sender) {
445
+ const messageDiv = document.createElement('div');
446
+ messageDiv.className = `message-${sender} p-3 max-w-[80%] ${sender === 'user' ? 'ml-auto' : ''}`;
447
+
448
+ // Check if markdown is enabled
449
+ chrome.storage.sync.get(['markdownEnabled'], (result) => {
450
+ if (result.markdownEnabled) {
451
+ // Simple markdown parsing (bold, italic, links)
452
+ text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
453
+ text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
454
+ text = text.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" class="text-indigo-400 hover:underline" target="_blank">$1</a>');
455
+ }
456
+
457
+ messageDiv.innerHTML = `<p class="text-sm">${text}</p>`;
458
+ chatMessages.appendChild(messageDiv);
459
+
460
+ // Check if animations are enabled
461
+ chrome.storage.sync.get(['animationsEnabled'], (result) => {
462
+ if (result.animationsEnabled) {
463
+ messageDiv.style.opacity = '0';
464
+ messageDiv.style.transform = 'translateY(10px)';
465
+ messageDiv.style.transition = 'all 0.3s ease';
466
+ setTimeout(() => {
467
+ messageDiv.style.opacity = '1';
468
+ messageDiv.style.transform = 'translateY(0)';
469
+ }, 10);
470
+ }
471
+ });
472
+
473
+ chatMessages.scrollTop = chatMessages.scrollHeight;
474
+ });
475
+ }
476
+
477
+ function applyMessageStyle(style) {
478
+ const messages = document.querySelectorAll('.message-user, .message-ai');
479
+
480
+ messages.forEach(msg => {
481
+ msg.classList.remove('rounded-12px', 'rounded-none', 'rounded-full');
482
+
483
+ switch(style) {
484
+ case 'rounded':
485
+ msg.classList.add('rounded-[12px]');
486
+ break;
487
+ case 'square':
488
+ msg.classList.add('rounded-none');
489
+ break;
490
+ case 'bubble':
491
+ msg.classList.add('rounded-full');
492
+ break;
493
+ }
494
+ });
495
+ }
496
+
497
+ function applyFontSize(size) {
498
+ const messages = document.querySelectorAll('.message-user p, .message-ai p');
499
+
500
+ messages.forEach(msg => {
501
+ msg.classList.remove('text-xs', 'text-sm', 'text-base');
502
+
503
+ switch(size) {
504
+ case 'small':
505
+ msg.classList.add('text-xs');
506
+ break;
507
+ case 'medium':
508
+ msg.classList.add('text-sm');
509
+ break;
510
+ case 'large':
511
+ msg.classList.add('text-base');
512
+ break;
513
+ }
514
+ });
515
+ }
516
+
517
+ function applyTheme(theme) {
518
+ if (theme === 'system') {
519
+ theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
520
+ }
521
+
522
+ document.documentElement.classList.remove('light', 'dark');
523
+ document.documentElement.classList.add(theme);
524
+
525
+ // Update UI elements based on theme
526
+ const header = document.querySelector('header');
527
+ const modal = document.querySelector('#settings-modal > div');
528
+
529
+ if (theme === 'dark') {
530
+ header.classList.add('header-dark');
531
+ header.classList.remove('bg-white');
532
+ modal.classList.add('modal-dark');
533
+ modal.classList.remove('bg-white');
534
+ } else {
535
+ header.classList.remove('header-dark');
536
+ header.classList.add('bg-white');
537
+ modal.classList.remove('modal-dark');
538
+ modal.classList.add('bg-white');
539
+ }
540
+ }
541
+
542
+ function showNotification(message) {
543
+ const notification = document.createElement('div');
544
+ notification.className = 'fixed bottom-4 right-4 bg-green-600 text-white px-4 py-2 rounded-md text-sm shadow-lg';
545
+ notification.textContent = message;
546
+ document.body.appendChild(notification);
547
+
548
+ setTimeout(() => {
549
+ notification.classList.add('opacity-0', 'transition-opacity', 'duration-300');
550
+ setTimeout(() => {
551
+ document.body.removeChild(notification);
552
+ }, 300);
553
+ }, 3000);
554
+ }
555
+
556
+ // Load prompt library and AI role
557
+ document.getElementById('prompt-library').addEventListener('change', function() {
558
+ if (this.value) {
559
+ document.getElementById('ai-role').value = '';
560
+ }
561
+ });
562
+
563
+ document.getElementById('ai-role').addEventListener('input', function() {
564
+ if (this.value) {
565
+ document.getElementById('prompt-library').value = '';
566
+ }
567
+ });
568
+
569
+ // Load saved role and prompt
570
+ chrome.storage.sync.get(['aiRole', 'selectedPrompt'], (result) => {
571
+ if (result.aiRole) {
572
+ document.getElementById('ai-role').value = result.aiRole;
573
+ }
574
+ if (result.selectedPrompt) {
575
+ document.getElementById('prompt-library').value = result.selectedPrompt;
576
+ }
577
+ });
578
+ </script>
579
+ </body>
580
  </html>