@pheem49/mint 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/BUILD_AND_RELEASE.md +75 -0
  2. package/LICENSE +654 -0
  3. package/README.md +165 -0
  4. package/assets/Agent_Mint.png +0 -0
  5. package/assets/CLI_Screen.png +0 -0
  6. package/assets/Settings.png +0 -0
  7. package/assets/icon.png +0 -0
  8. package/benchmark_ai.js +71 -0
  9. package/main.js +968 -0
  10. package/mint-cli-logic.js +71 -0
  11. package/mint-cli.js +239 -0
  12. package/package.json +60 -0
  13. package/preload-picker.js +11 -0
  14. package/preload-settings.js +11 -0
  15. package/preload.js +37 -0
  16. package/privacy.txt +1 -0
  17. package/src/AI_Brain/Gemini_API.js +419 -0
  18. package/src/AI_Brain/autonomous_brain.js +139 -0
  19. package/src/AI_Brain/behavior_memory.js +114 -0
  20. package/src/AI_Brain/headless_agent.js +120 -0
  21. package/src/AI_Brain/knowledge_base.js +222 -0
  22. package/src/AI_Brain/proactive_engine.js +168 -0
  23. package/src/Automation_Layer/browser_automation.js +147 -0
  24. package/src/Automation_Layer/file_operations.js +80 -0
  25. package/src/Automation_Layer/open_app.js +56 -0
  26. package/src/Automation_Layer/open_website.js +38 -0
  27. package/src/CLI/chat_ui.js +468 -0
  28. package/src/CLI/list_features.js +56 -0
  29. package/src/CLI/onboarding.js +60 -0
  30. package/src/Command_Parser/parser.js +34 -0
  31. package/src/Plugins/dev_tools.js +41 -0
  32. package/src/Plugins/discord.js +20 -0
  33. package/src/Plugins/docker.js +45 -0
  34. package/src/Plugins/google_calendar.js +26 -0
  35. package/src/Plugins/obsidian.js +54 -0
  36. package/src/Plugins/plugin_manager.js +81 -0
  37. package/src/Plugins/spotify.js +45 -0
  38. package/src/Plugins/system_metrics.js +31 -0
  39. package/src/System/chat_history_manager.js +57 -0
  40. package/src/System/config_manager.js +73 -0
  41. package/src/System/custom_workflows.js +127 -0
  42. package/src/System/daemon_manager.js +67 -0
  43. package/src/System/system_automation.js +88 -0
  44. package/src/System/system_events.js +79 -0
  45. package/src/System/system_info.js +55 -0
  46. package/src/System/task_manager.js +85 -0
  47. package/src/UI/floating.css +80 -0
  48. package/src/UI/floating.html +17 -0
  49. package/src/UI/floating.js +67 -0
  50. package/src/UI/index.html +126 -0
  51. package/src/UI/preload-floating.js +7 -0
  52. package/src/UI/preload-spotlight.js +10 -0
  53. package/src/UI/preload-widget.js +5 -0
  54. package/src/UI/proactive-glow.html +42 -0
  55. package/src/UI/renderer.js +978 -0
  56. package/src/UI/screenPicker.html +214 -0
  57. package/src/UI/screenPicker.js +262 -0
  58. package/src/UI/settings.css +705 -0
  59. package/src/UI/settings.html +396 -0
  60. package/src/UI/settings.js +514 -0
  61. package/src/UI/spotlight.css +119 -0
  62. package/src/UI/spotlight.html +23 -0
  63. package/src/UI/spotlight.js +181 -0
  64. package/src/UI/styles.css +627 -0
  65. package/src/UI/widget.css +218 -0
  66. package/src/UI/widget.html +29 -0
  67. package/src/UI/widget.js +10 -0
  68. package/tech_news.txt +3 -0
  69. package/test_knowledge.txt +3 -0
@@ -0,0 +1,514 @@
1
+ const DEFAULT_CONFIG = {
2
+ theme: 'dark',
3
+ accentColor: '#8b5cf6',
4
+ systemTextColor: '#f8fafc',
5
+ customBgStart: '#0f172a',
6
+ customBgEnd: '#1e1b4b',
7
+ customPanelBg: '#1e293b',
8
+ apiKey: '',
9
+ geminiModel: 'gemini-3.1-flash-lite-preview',
10
+ language: 'th-TH',
11
+ proactiveInterval: 60,
12
+ proactiveCooldown: 120,
13
+ glassBlur: 'blur(16px)',
14
+ fontFamily: "'Outfit', sans-serif",
15
+ aiProvider: 'gemini',
16
+ ollamaModel: 'llama3:latest',
17
+ enableVoiceReply: true,
18
+ enableCustomWorkflows: true,
19
+ ttsProvider: 'google',
20
+ ttsVolume: 1.0,
21
+ ttsSpeed: 1.0,
22
+ ttsPitch: 1.0,
23
+ pluginSpotifyEnabled: true,
24
+ pluginCalendarEnabled: false,
25
+ pluginDiscordEnabled: false,
26
+ showDesktopWidget: true
27
+ };
28
+
29
+ let currentConfig = { ...DEFAULT_CONFIG };
30
+
31
+ // Load settings from main process
32
+ async function loadSettings() {
33
+ const config = await window.settingsApi.getSettings();
34
+ currentConfig = { ...DEFAULT_CONFIG, ...config };
35
+ applyConfig(currentConfig);
36
+ }
37
+
38
+ function applyConfig(config) {
39
+ // Apply theme
40
+ document.documentElement.setAttribute('data-theme', config.theme);
41
+
42
+ if (config.theme === 'custom') {
43
+ document.getElementById('custom-theme-controls').style.display = 'block';
44
+ applyCustomThemeStyles(config);
45
+ } else {
46
+ document.getElementById('custom-theme-controls').style.display = 'none';
47
+ // Reset dynamic style variables if not custom
48
+ document.documentElement.style.removeProperty('--bg-gradient');
49
+ document.documentElement.style.removeProperty('--panel-bg');
50
+ }
51
+
52
+ // Apply accent color
53
+ document.documentElement.style.setProperty('--accent', config.accentColor);
54
+ document.documentElement.style.setProperty('--accent-hover', lightenColor(config.accentColor, 20));
55
+
56
+ // Apply API key
57
+ document.getElementById('api-key-input').value = config.apiKey || '';
58
+
59
+ // Apply Gemini model
60
+ applyModelSelection(config.geminiModel);
61
+
62
+ // Apply AI Provider
63
+ const providerSelect = document.getElementById('ai-provider-select');
64
+ if (providerSelect) {
65
+ providerSelect.value = config.aiProvider || 'gemini';
66
+ toggleProviderOptions(providerSelect.value);
67
+ }
68
+
69
+ const ollamaInput = document.getElementById('ollama-model-input');
70
+ if (ollamaInput) {
71
+ ollamaInput.value = config.ollamaModel || 'llama3:latest';
72
+ }
73
+
74
+ const voiceReplyToggle = document.getElementById('enable-voice-reply');
75
+ if (voiceReplyToggle) {
76
+ voiceReplyToggle.checked = config.enableVoiceReply !== false;
77
+ }
78
+
79
+ const ttsProviderSelect = document.getElementById('tts-provider-select');
80
+ if (ttsProviderSelect) ttsProviderSelect.value = config.ttsProvider || 'google';
81
+
82
+ const ttsVolume = document.getElementById('tts-volume');
83
+ if (ttsVolume) {
84
+ ttsVolume.value = config.ttsVolume !== undefined ? config.ttsVolume : 1.0;
85
+ document.getElementById('tts-volume-val').textContent = `${Math.round(ttsVolume.value * 100)}%`;
86
+ }
87
+
88
+ const ttsSpeed = document.getElementById('tts-speed');
89
+ if (ttsSpeed) {
90
+ ttsSpeed.value = config.ttsSpeed !== undefined ? config.ttsSpeed : 1.0;
91
+ document.getElementById('tts-speed-val').textContent = `${parseFloat(ttsSpeed.value).toFixed(1)}x`;
92
+ }
93
+
94
+ const ttsPitch = document.getElementById('tts-pitch');
95
+ if (ttsPitch) {
96
+ ttsPitch.value = config.ttsPitch !== undefined ? config.ttsPitch : 1.0;
97
+ document.getElementById('tts-pitch-val').textContent = parseFloat(ttsPitch.value).toFixed(1);
98
+ }
99
+
100
+ const enableWorkflowsToggle = document.getElementById('enable-custom-workflows');
101
+ if (enableWorkflowsToggle) {
102
+ enableWorkflowsToggle.checked = config.enableCustomWorkflows !== false;
103
+ }
104
+
105
+ // Plugins logic
106
+ updatePluginButton('spotify', config.pluginSpotifyEnabled);
107
+ updatePluginButton('calendar', config.pluginCalendarEnabled);
108
+ updatePluginButton('discord', config.pluginDiscordEnabled);
109
+
110
+ // Apply Automation Browser
111
+ if (config.automationBrowser) {
112
+ document.getElementById('automation-browser-select').value = config.automationBrowser;
113
+ }
114
+
115
+ const showWidgetToggle = document.getElementById('show-desktop-widget');
116
+ if (showWidgetToggle) {
117
+ showWidgetToggle.checked = config.showDesktopWidget !== false;
118
+ }
119
+
120
+ // Apply UI Customizations
121
+ document.getElementById('glass-blur-select').value = config.glassBlur || 'blur(16px)';
122
+ document.documentElement.style.setProperty('--glass-blur', config.glassBlur || 'blur(16px)');
123
+
124
+ document.getElementById('font-family-select').value = config.fontFamily || "'Outfit', sans-serif";
125
+ document.body.style.fontFamily = config.fontFamily || "'Outfit', sans-serif";
126
+
127
+ // Update active theme card
128
+ document.querySelectorAll('.theme-card').forEach(card => {
129
+ card.classList.toggle('active', card.dataset.theme === config.theme);
130
+ });
131
+
132
+ // Update active color dot
133
+ document.querySelectorAll('.color-dot').forEach(dot => {
134
+ dot.classList.toggle('active', dot.dataset.color === config.accentColor);
135
+ });
136
+
137
+ // Update color picker
138
+ document.getElementById('custom-color').value = config.accentColor;
139
+
140
+ document.getElementById('system-text-color').value = textColor;
141
+ document.documentElement.style.setProperty('--text-main', textColor);
142
+
143
+ // Update custom color pickers
144
+ document.getElementById('custom-bg-start').value = config.customBgStart || '#0f172a';
145
+ document.getElementById('custom-bg-end').value = config.customBgEnd || '#1e1b4b';
146
+ document.getElementById('custom-panel-bg').value = config.customPanelBg || '#1e293b';
147
+ updateCustomPreviewBox(config);
148
+
149
+ // Apply proactive settings
150
+ const interval = config.proactiveInterval || 60;
151
+ const cooldown = config.proactiveCooldown || 120;
152
+ document.getElementById('proactive-interval').value = interval;
153
+ document.getElementById('proactive-cooldown').value = cooldown;
154
+ updateIntervalDisplay(interval);
155
+ updateCooldownDisplay(cooldown);
156
+ }
157
+
158
+ function lightenColor(hex, amount) {
159
+ const num = parseInt(hex.replace('#', ''), 16);
160
+ const r = Math.min(255, (num >> 16) + amount);
161
+ const g = Math.min(255, ((num >> 8) & 0x00FF) + amount);
162
+ const b = Math.min(255, (num & 0x0000FF) + amount);
163
+ return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
164
+ }
165
+
166
+ function applyModelSelection(model) {
167
+ const select = document.getElementById('gemini-model-select');
168
+ const customRow = document.getElementById('gemini-model-custom-row');
169
+ const customInput = document.getElementById('gemini-model-custom');
170
+ const normalized = (model || '').trim();
171
+ const optionValues = Array.from(select.options).map(opt => opt.value);
172
+
173
+ if (normalized && optionValues.includes(normalized)) {
174
+ select.value = normalized;
175
+ customRow.style.display = 'none';
176
+ customInput.value = '';
177
+ } else {
178
+ select.value = 'custom';
179
+ customRow.style.display = 'block';
180
+ customInput.value = normalized;
181
+ }
182
+ }
183
+
184
+ function getSelectedModel() {
185
+ const select = document.getElementById('gemini-model-select');
186
+ const customInput = document.getElementById('gemini-model-custom');
187
+ if (select.value === 'custom') {
188
+ const custom = (customInput.value || '').trim();
189
+ return custom || DEFAULT_CONFIG.geminiModel;
190
+ }
191
+ return select.value;
192
+ }
193
+
194
+ // --- Event Listeners ---
195
+
196
+ // Close button
197
+ document.getElementById('close-btn').addEventListener('click', () => {
198
+ window.settingsApi.closeSettings();
199
+ });
200
+
201
+ // Toggle API key visibility
202
+ document.getElementById('toggle-key').addEventListener('click', () => {
203
+ const input = document.getElementById('api-key-input');
204
+ input.type = input.type === 'password' ? 'text' : 'password';
205
+ });
206
+
207
+ async function saveApiKeyOnly() {
208
+ const input = document.getElementById('api-key-input');
209
+ const status = document.getElementById('api-save-status');
210
+ const btn = document.getElementById('save-api-key');
211
+ const apiKey = input.value.trim();
212
+
213
+ try {
214
+ const baseConfig = await window.settingsApi.getSettings();
215
+ const nextConfig = { ...baseConfig, apiKey };
216
+ await window.settingsApi.saveSettings(nextConfig);
217
+ currentConfig.apiKey = apiKey;
218
+
219
+ btn.textContent = 'Saved!';
220
+ status.textContent = 'API key saved';
221
+ setTimeout(() => {
222
+ btn.textContent = 'Save API Key';
223
+ status.textContent = '';
224
+ }, 1500);
225
+ } catch (err) {
226
+ console.error('Failed to save API key:', err);
227
+ status.textContent = 'Save failed';
228
+ setTimeout(() => { status.textContent = ''; }, 1500);
229
+ }
230
+ }
231
+
232
+ document.getElementById('save-api-key').addEventListener('click', saveApiKeyOnly);
233
+ document.getElementById('api-key-input').addEventListener('keydown', (e) => {
234
+ if (e.key === 'Enter') {
235
+ e.preventDefault();
236
+ saveApiKeyOnly();
237
+ }
238
+ });
239
+
240
+ // Gemini model select
241
+ document.getElementById('gemini-model-select').addEventListener('change', (e) => {
242
+ const customRow = document.getElementById('gemini-model-custom-row');
243
+ if (e.target.value === 'custom') {
244
+ customRow.style.display = 'block';
245
+ currentConfig.geminiModel = (document.getElementById('gemini-model-custom').value || '').trim();
246
+ } else {
247
+ customRow.style.display = 'none';
248
+ currentConfig.geminiModel = e.target.value;
249
+ }
250
+ });
251
+
252
+ document.getElementById('gemini-model-custom').addEventListener('input', (e) => {
253
+ currentConfig.geminiModel = e.target.value.trim();
254
+ });
255
+
256
+ // AI Provider toggle
257
+ function toggleProviderOptions(provider) {
258
+ const geminiOptions = document.getElementById('gemini-options');
259
+ const ollamaOptions = document.getElementById('ollama-options');
260
+
261
+ if (provider === 'ollama') {
262
+ geminiOptions.style.display = 'none';
263
+ ollamaOptions.style.display = 'block';
264
+ } else {
265
+ geminiOptions.style.display = 'block';
266
+ ollamaOptions.style.display = 'none';
267
+ }
268
+ }
269
+
270
+ document.getElementById('ai-provider-select').addEventListener('change', (e) => {
271
+ currentConfig.aiProvider = e.target.value;
272
+ toggleProviderOptions(e.target.value);
273
+ });
274
+
275
+ document.getElementById('ollama-model-input').addEventListener('input', (e) => {
276
+ currentConfig.ollamaModel = e.target.value.trim();
277
+ });
278
+
279
+ // AI Studio link
280
+ document.getElementById('ai-studio-link').addEventListener('click', () => {
281
+ window.settingsApi.openExternal('https://aistudio.google.com/');
282
+ });
283
+
284
+ // Theme cards
285
+ document.querySelectorAll('.theme-card').forEach(card => {
286
+ card.addEventListener('click', () => {
287
+ currentConfig.theme = card.dataset.theme;
288
+ applyConfig(currentConfig);
289
+ });
290
+ });
291
+
292
+ // Color presets
293
+ document.querySelectorAll('.color-dot').forEach(dot => {
294
+ dot.addEventListener('click', () => {
295
+ currentConfig.accentColor = dot.dataset.color;
296
+ applyConfig(currentConfig);
297
+ document.getElementById('custom-color').value = dot.dataset.color;
298
+ });
299
+ });
300
+
301
+ // Custom color picker
302
+ document.getElementById('custom-color').addEventListener('input', (e) => {
303
+ currentConfig.accentColor = e.target.value;
304
+ document.documentElement.style.setProperty('--accent', e.target.value);
305
+ document.documentElement.style.setProperty('--accent-hover', lightenColor(e.target.value, 20));
306
+ // Deselect presets
307
+ document.querySelectorAll('.color-dot').forEach(dot => dot.classList.remove('active'));
308
+ });
309
+
310
+ // System text color picker
311
+ document.getElementById('system-text-color').addEventListener('input', (e) => {
312
+ currentConfig.systemTextColor = e.target.value;
313
+ document.documentElement.style.setProperty('--text-main', e.target.value);
314
+ });
315
+
316
+ // Custom Theme color pickers
317
+ function applyCustomThemeStyles(cfg) {
318
+ const gradient = `linear-gradient(135deg, ${cfg.customBgStart} 0%, ${cfg.customBgEnd} 100%)`;
319
+ document.documentElement.style.setProperty('--bg-gradient', gradient);
320
+
321
+ // Convert hex to rgba for panel bg to keep transparency
322
+ const panelRgb = hexToRgb(cfg.customPanelBg);
323
+ document.documentElement.style.setProperty('--panel-bg', `rgba(${panelRgb.r}, ${panelRgb.g}, ${panelRgb.b}, 0.75)`);
324
+ updateCustomPreviewBox(cfg);
325
+ }
326
+
327
+ function updateCustomPreviewBox(cfg) {
328
+ const box = document.getElementById('custom-theme-preview-box');
329
+ if (box) {
330
+ box.style.background = `linear-gradient(135deg, ${cfg.customBgStart} 0%, ${cfg.customBgEnd} 100%)`;
331
+ }
332
+ }
333
+
334
+ function hexToRgb(hex) {
335
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
336
+ return result ? {
337
+ r: parseInt(result[1], 16),
338
+ g: parseInt(result[2], 16),
339
+ b: parseInt(result[3], 16)
340
+ } : { r: 30, g: 41, b: 59 };
341
+ }
342
+
343
+ document.getElementById('custom-bg-start').addEventListener('input', (e) => {
344
+ currentConfig.customBgStart = e.target.value;
345
+ if (currentConfig.theme === 'custom') applyCustomThemeStyles(currentConfig);
346
+ });
347
+ document.getElementById('custom-bg-end').addEventListener('input', (e) => {
348
+ currentConfig.customBgEnd = e.target.value;
349
+ if (currentConfig.theme === 'custom') applyCustomThemeStyles(currentConfig);
350
+ });
351
+ document.getElementById('custom-panel-bg').addEventListener('input', (e) => {
352
+ currentConfig.customPanelBg = e.target.value;
353
+ if (currentConfig.theme === 'custom') applyCustomThemeStyles(currentConfig);
354
+ });
355
+
356
+ // Proactive sliders
357
+ function formatSeconds(s) {
358
+ if (s < 60) return `${s} sec`;
359
+ const m = s / 60;
360
+ return Number.isInteger(m) ? `${m} min` : `${m.toFixed(1)} min`;
361
+ }
362
+
363
+ function updateIntervalDisplay(val) {
364
+ document.getElementById('proactive-interval-display').textContent = formatSeconds(Number(val));
365
+ }
366
+
367
+ function updateCooldownDisplay(val) {
368
+ document.getElementById('proactive-cooldown-display').textContent = formatSeconds(Number(val));
369
+ }
370
+
371
+ document.getElementById('proactive-interval').addEventListener('input', (e) => {
372
+ updateIntervalDisplay(e.target.value);
373
+ });
374
+
375
+ document.getElementById('proactive-cooldown').addEventListener('input', (e) => {
376
+ updateCooldownDisplay(e.target.value);
377
+ });
378
+
379
+ // TTS slider UI updates
380
+ if (document.getElementById('tts-volume')) {
381
+ document.getElementById('tts-volume').addEventListener('input', (e) => {
382
+ document.getElementById('tts-volume-val').textContent = `${Math.round(e.target.value * 100)}%`;
383
+ });
384
+ }
385
+ if (document.getElementById('tts-speed')) {
386
+ document.getElementById('tts-speed').addEventListener('input', (e) => {
387
+ document.getElementById('tts-speed-val').textContent = `${parseFloat(e.target.value).toFixed(1)}x`;
388
+ });
389
+ }
390
+ if (document.getElementById('tts-pitch')) {
391
+ document.getElementById('tts-pitch').addEventListener('input', (e) => {
392
+ document.getElementById('tts-pitch-val').textContent = parseFloat(e.target.value).toFixed(1);
393
+ });
394
+ }
395
+
396
+ // Save
397
+ document.getElementById('save-btn').addEventListener('click', async () => {
398
+ currentConfig.apiKey = document.getElementById('api-key-input').value.trim();
399
+ currentConfig.geminiModel = getSelectedModel();
400
+ currentConfig.aiProvider = document.getElementById('ai-provider-select').value;
401
+ currentConfig.ollamaModel = document.getElementById('ollama-model-input').value.trim();
402
+
403
+ const voiceReplyToggle = document.getElementById('enable-voice-reply');
404
+ if (voiceReplyToggle) {
405
+ currentConfig.enableVoiceReply = voiceReplyToggle.checked;
406
+ }
407
+
408
+ const ttsProviderSelect = document.getElementById('tts-provider-select');
409
+ if (ttsProviderSelect) currentConfig.ttsProvider = ttsProviderSelect.value;
410
+
411
+ if (document.getElementById('tts-volume')) currentConfig.ttsVolume = parseFloat(document.getElementById('tts-volume').value);
412
+ if (document.getElementById('tts-speed')) currentConfig.ttsSpeed = parseFloat(document.getElementById('tts-speed').value);
413
+ if (document.getElementById('tts-pitch')) currentConfig.ttsPitch = parseFloat(document.getElementById('tts-pitch').value);
414
+
415
+ const enableWorkflowsToggle = document.getElementById('enable-custom-workflows');
416
+ if (enableWorkflowsToggle) {
417
+ currentConfig.enableCustomWorkflows = enableWorkflowsToggle.checked;
418
+ }
419
+
420
+ const showWidgetToggle = document.getElementById('show-desktop-widget');
421
+ if (showWidgetToggle) {
422
+ currentConfig.showDesktopWidget = showWidgetToggle.checked;
423
+ }
424
+
425
+ currentConfig.automationBrowser = document.getElementById('automation-browser-select').value;
426
+ currentConfig.proactiveInterval = Number(document.getElementById('proactive-interval').value);
427
+ currentConfig.proactiveCooldown = Number(document.getElementById('proactive-cooldown').value);
428
+ currentConfig.systemTextColor = document.getElementById('system-text-color').value;
429
+ currentConfig.glassBlur = document.getElementById('glass-blur-select').value;
430
+ currentConfig.fontFamily = document.getElementById('font-family-select').value;
431
+
432
+ currentConfig.customBgStart = document.getElementById('custom-bg-start').value;
433
+ currentConfig.customBgEnd = document.getElementById('custom-bg-end').value;
434
+ currentConfig.customPanelBg = document.getElementById('custom-panel-bg').value;
435
+
436
+ await window.settingsApi.saveSettings(currentConfig);
437
+ const btn = document.getElementById('save-btn');
438
+ btn.textContent = '✅ Saved!';
439
+ setTimeout(() => { btn.textContent = 'Save Settings'; }, 1500);
440
+ });
441
+
442
+ // Custom Workflows functionality
443
+ const openWorkflowsBtn = document.getElementById('open-workflows-btn');
444
+ const reloadWorkflowsBtn = document.getElementById('reload-workflows-btn');
445
+ if (openWorkflowsBtn) {
446
+ openWorkflowsBtn.addEventListener('click', () => {
447
+ window.settingsApi.openCustomWorkflows();
448
+ });
449
+ }
450
+ if (reloadWorkflowsBtn) {
451
+ reloadWorkflowsBtn.addEventListener('click', async () => {
452
+ await window.settingsApi.reloadCustomWorkflows();
453
+ const originalText = reloadWorkflowsBtn.textContent;
454
+ reloadWorkflowsBtn.textContent = '✅ Reloaded!';
455
+ setTimeout(() => { reloadWorkflowsBtn.textContent = originalText; }, 1500);
456
+ });
457
+ }
458
+
459
+ // Quit App
460
+ document.getElementById('quit-btn').addEventListener('click', () => {
461
+ if (confirm('Are you sure you want to quit Mint?')) {
462
+ window.settingsApi.quitApp();
463
+ }
464
+ });
465
+
466
+ // Reset to default
467
+ document.getElementById('reset-btn').addEventListener('click', () => {
468
+ currentConfig = { ...DEFAULT_CONFIG };
469
+ applyConfig(currentConfig);
470
+ });
471
+
472
+ function updatePluginButton(pluginName, isEnabled) {
473
+ const btn = document.getElementById(`btn-plugin-${pluginName}`);
474
+ if (!btn) return;
475
+
476
+ if (isEnabled) {
477
+ btn.textContent = 'Disconnect';
478
+ btn.classList.remove('btn-connect');
479
+ btn.classList.add('btn-disconnect');
480
+ } else {
481
+ btn.textContent = 'Connect';
482
+ btn.classList.add('btn-connect');
483
+ btn.classList.remove('btn-disconnect');
484
+ }
485
+ }
486
+
487
+ // Bind plugin buttons
488
+ ['spotify', 'calendar', 'discord'].forEach(plugin => {
489
+ const btn = document.getElementById(`btn-plugin-${plugin}`);
490
+ if (btn) {
491
+ btn.addEventListener('click', () => {
492
+ const key = `plugin${plugin.charAt(0).toUpperCase() + plugin.slice(1)}Enabled`;
493
+ currentConfig[key] = !currentConfig[key];
494
+ updatePluginButton(plugin, currentConfig[key]);
495
+ });
496
+ }
497
+ });
498
+
499
+ // Init
500
+ // Sidebar Tab Navigation
501
+ document.querySelectorAll('.tab-btn').forEach(btn => {
502
+ btn.addEventListener('click', () => {
503
+ const target = btn.dataset.target;
504
+ // Deactivate all
505
+ document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
506
+ document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
507
+ // Activate selected
508
+ btn.classList.add('active');
509
+ const pane = document.getElementById(target);
510
+ if (pane) pane.classList.add('active');
511
+ });
512
+ });
513
+
514
+ window.addEventListener('DOMContentLoaded', loadSettings);
@@ -0,0 +1,119 @@
1
+ :root {
2
+ --bg-color: rgba(15, 23, 42, 0.85);
3
+ --accent: #8b5cf6;
4
+ --text-main: #f8fafc;
5
+ --text-muted: #94a3b8;
6
+ --border: rgba(255, 255, 255, 0.1);
7
+ --glass-blur: blur(20px);
8
+ }
9
+
10
+ body {
11
+ margin: 0;
12
+ padding: 0;
13
+ font-family: 'Outfit', sans-serif;
14
+ background: transparent;
15
+ overflow: hidden;
16
+ user-select: none;
17
+ }
18
+
19
+ .spotlight-container {
20
+ width: 100vw;
21
+ height: auto;
22
+ background: var(--bg-color);
23
+ backdrop-filter: var(--glass-blur);
24
+ -webkit-backdrop-filter: var(--glass-blur);
25
+ border-radius: 16px;
26
+ border: 1px solid var(--border);
27
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05);
28
+ overflow: hidden;
29
+ }
30
+
31
+ .input-wrapper {
32
+ display: flex;
33
+ align-items: center;
34
+ padding: 16px 20px;
35
+ gap: 15px;
36
+ }
37
+
38
+ .spotlight-icon {
39
+ font-size: 1.5rem;
40
+ animation: glow 2s ease-in-out infinite alternate;
41
+ }
42
+
43
+ @keyframes glow {
44
+ from { filter: drop-shadow(0 0 2px rgba(139, 92, 246, 0.5)); }
45
+ to { filter: drop-shadow(0 0 8px rgba(167, 139, 250, 0.8)); }
46
+ }
47
+
48
+ #spotlight-input {
49
+ flex: 1;
50
+ background: transparent;
51
+ border: none;
52
+ outline: none;
53
+ color: var(--text-main);
54
+ font-size: 1.2rem;
55
+ font-family: inherit;
56
+ }
57
+
58
+ #spotlight-input::placeholder {
59
+ color: var(--text-muted);
60
+ }
61
+
62
+ .shortcut-tip {
63
+ font-size: 0.7rem;
64
+ color: var(--text-muted);
65
+ background: rgba(255, 255, 255, 0.05);
66
+ padding: 4px 8px;
67
+ border-radius: 6px;
68
+ border: 1px solid var(--border);
69
+ text-transform: uppercase;
70
+ letter-spacing: 0.5px;
71
+ }
72
+
73
+ .results-container {
74
+ border-top: 1px solid var(--border);
75
+ max-height: 400px;
76
+ overflow-y: auto;
77
+ padding: 8px;
78
+ }
79
+
80
+ .result-item {
81
+ display: flex;
82
+ align-items: center;
83
+ padding: 12px 14px;
84
+ border-radius: 12px;
85
+ gap: 12px;
86
+ cursor: pointer;
87
+ transition: all 0.2s;
88
+ }
89
+
90
+ .result-item:hover, .result-item.selected {
91
+ background: rgba(139, 92, 246, 0.2);
92
+ }
93
+
94
+ .result-icon {
95
+ width: 32px;
96
+ height: 32px;
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ background: rgba(0, 0, 0, 0.2);
101
+ border-radius: 8px;
102
+ font-size: 1.1rem;
103
+ }
104
+
105
+ .result-content {
106
+ flex: 1;
107
+ }
108
+
109
+ .result-title {
110
+ font-weight: 500;
111
+ color: var(--text-main);
112
+ font-size: 0.95rem;
113
+ }
114
+
115
+ .result-desc {
116
+ font-size: 0.8rem;
117
+ color: var(--text-muted);
118
+ margin-top: 2px;
119
+ }
@@ -0,0 +1,23 @@
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>Mint Spotlight</title>
7
+ <link rel="stylesheet" href="spotlight.css">
8
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600&display=swap" rel="stylesheet">
9
+ </head>
10
+ <body>
11
+ <div class="spotlight-container">
12
+ <div class="input-wrapper">
13
+ <div class="spotlight-icon">✨</div>
14
+ <input type="text" id="spotlight-input" placeholder="What can I help with?" autocomplete="off" autofocus>
15
+ <div class="shortcut-tip">ESC to close</div>
16
+ </div>
17
+ <div id="spotlight-results" class="results-container" style="display: none;">
18
+ <!-- Results will be injected here -->
19
+ </div>
20
+ </div>
21
+ <script src="spotlight.js"></script>
22
+ </body>
23
+ </html>