mani-calc 1.2.2 → 2.1.0

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.
@@ -27,16 +27,103 @@
27
27
  --shortcut-bg: rgba(0, 0, 0, 0.02);
28
28
  --key-bg: rgba(0, 0, 0, 0.1);
29
29
  --border-color: rgba(0, 0, 0, 0.1);
30
+ --result-bg: rgba(0, 217, 255, 0.05);
30
31
  }
31
32
 
33
+ /* Dark Theme (default) */
32
34
  body.dark {
33
35
  --bg-color: rgba(30, 30, 30, 0.95);
34
36
  --text-color: #eee;
35
37
  --icon-color: #00D9FF;
36
- --hint-color: #666;
38
+ --hint-color: #888;
37
39
  --shortcut-bg: rgba(255, 255, 255, 0.05);
38
40
  --key-bg: rgba(255, 255, 255, 0.1);
39
41
  --border-color: rgba(255, 255, 255, 0.1);
42
+ --result-bg: rgba(0, 217, 255, 0.08);
43
+ }
44
+
45
+ /* Midnight Blue Theme */
46
+ body.midnight {
47
+ --bg-color: rgba(10, 22, 40, 0.95);
48
+ --text-color: #e0e8f0;
49
+ --icon-color: #4a9eff;
50
+ --hint-color: #6a8aaa;
51
+ --shortcut-bg: rgba(74, 158, 255, 0.05);
52
+ --key-bg: rgba(74, 158, 255, 0.15);
53
+ --border-color: rgba(74, 158, 255, 0.2);
54
+ --result-bg: rgba(74, 158, 255, 0.1);
55
+ }
56
+
57
+ /* Forest Green Theme */
58
+ body.forest {
59
+ --bg-color: rgba(26, 47, 26, 0.95);
60
+ --text-color: #d0e8d0;
61
+ --icon-color: #4caf50;
62
+ --hint-color: #7ab87a;
63
+ --shortcut-bg: rgba(76, 175, 80, 0.05);
64
+ --key-bg: rgba(76, 175, 80, 0.15);
65
+ --border-color: rgba(76, 175, 80, 0.2);
66
+ --result-bg: rgba(76, 175, 80, 0.1);
67
+ }
68
+
69
+ /* Sunset Orange Theme */
70
+ body.sunset {
71
+ --bg-color: rgba(45, 26, 26, 0.95);
72
+ --text-color: #f0e0d8;
73
+ --icon-color: #ff6b35;
74
+ --hint-color: #cc8866;
75
+ --shortcut-bg: rgba(255, 107, 53, 0.05);
76
+ --key-bg: rgba(255, 107, 53, 0.15);
77
+ --border-color: rgba(255, 107, 53, 0.2);
78
+ --result-bg: rgba(255, 107, 53, 0.1);
79
+ }
80
+
81
+ /* Royal Purple Theme */
82
+ body.purple {
83
+ --bg-color: rgba(26, 26, 46, 0.95);
84
+ --text-color: #e8e0f0;
85
+ --icon-color: #9c27b0;
86
+ --hint-color: #aa77bb;
87
+ --shortcut-bg: rgba(156, 39, 176, 0.05);
88
+ --key-bg: rgba(156, 39, 176, 0.15);
89
+ --border-color: rgba(156, 39, 176, 0.2);
90
+ --result-bg: rgba(156, 39, 176, 0.1);
91
+ }
92
+
93
+ /* Neon Glow Theme */
94
+ body.neon {
95
+ --bg-color: rgba(13, 13, 13, 0.95);
96
+ --text-color: #f0fff0;
97
+ --icon-color: #39ff14;
98
+ --hint-color: #55aa44;
99
+ --shortcut-bg: rgba(57, 255, 20, 0.05);
100
+ --key-bg: rgba(57, 255, 20, 0.15);
101
+ --border-color: rgba(57, 255, 20, 0.3);
102
+ --result-bg: rgba(57, 255, 20, 0.08);
103
+ }
104
+
105
+ /* Deep Ocean Theme */
106
+ body.ocean {
107
+ --bg-color: rgba(10, 25, 41, 0.95);
108
+ --text-color: #e0f4f8;
109
+ --icon-color: #00bcd4;
110
+ --hint-color: #5599aa;
111
+ --shortcut-bg: rgba(0, 188, 212, 0.05);
112
+ --key-bg: rgba(0, 188, 212, 0.15);
113
+ --border-color: rgba(0, 188, 212, 0.2);
114
+ --result-bg: rgba(0, 188, 212, 0.1);
115
+ }
116
+
117
+ /* Light Theme */
118
+ body.light {
119
+ --bg-color: rgba(255, 255, 255, 0.98);
120
+ --text-color: #222;
121
+ --icon-color: #0066cc;
122
+ --hint-color: #666;
123
+ --shortcut-bg: rgba(0, 0, 0, 0.03);
124
+ --key-bg: rgba(0, 0, 0, 0.08);
125
+ --border-color: rgba(0, 0, 0, 0.1);
126
+ --result-bg: rgba(0, 102, 204, 0.05);
40
127
  }
41
128
 
42
129
  .container {
@@ -88,9 +175,12 @@
88
175
 
89
176
  .result-container {
90
177
  padding: 12px 20px;
91
- background: rgba(0, 217, 255, 0.05);
178
+ background: var(--result-bg);
92
179
  display: none;
93
180
  animation: slideDown 0.2s ease;
181
+ white-space: pre-wrap;
182
+ max-height: 300px;
183
+ overflow-y: auto;
94
184
  }
95
185
 
96
186
  .result-container.show {
@@ -204,6 +294,7 @@
204
294
  input.value = '';
205
295
  resultContainer.classList.remove('show');
206
296
  shortcuts.classList.remove('show');
297
+ ipcRenderer.send('resize-window', 80);
207
298
  });
208
299
 
209
300
  // Handle input
@@ -215,11 +306,11 @@
215
306
  return;
216
307
  }
217
308
 
218
- // Debounce for live preview
309
+ // Debounce for live preview (100ms for fast response)
219
310
  clearTimeout(debounceTimer);
220
311
  debounceTimer = setTimeout(() => {
221
312
  processQuery(query, true);
222
- }, 300);
313
+ }, 100);
223
314
  });
224
315
 
225
316
  // Handle Enter key
@@ -234,16 +325,66 @@
234
325
  }
235
326
  });
236
327
 
328
+ // Simple math evaluator for live preview
329
+ function evaluateMathExpression(expr) {
330
+ try {
331
+ // Clean the expression
332
+ let cleanExpr = expr.trim();
333
+
334
+ // Replace ^ with ** for exponentiation
335
+ cleanExpr = cleanExpr.replace(/\^/g, '**');
336
+
337
+ // Replace × with *
338
+ cleanExpr = cleanExpr.replace(/×/g, '*');
339
+
340
+ // Replace ÷ with /
341
+ cleanExpr = cleanExpr.replace(/÷/g, '/');
342
+
343
+ // Handle implicit multiplication (e.g., "2(3+4)" -> "2*(3+4)")
344
+ cleanExpr = cleanExpr.replace(/(\d)\(/g, '$1*(');
345
+
346
+ // Security: Only allow safe math characters
347
+ if (!/^[\d\s\+\-\*\/\(\)\.\,\%]+$/.test(cleanExpr)) {
348
+ return null;
349
+ }
350
+
351
+ // Handle percentage (e.g., "50%" -> "0.5")
352
+ cleanExpr = cleanExpr.replace(/(\d+(?:\.\d+)?)\s*%/g, '($1/100)');
353
+
354
+ // Evaluate using Function (safer than eval for math expressions)
355
+ const result = Function('"use strict"; return (' + cleanExpr + ')')();
356
+
357
+ // Check if result is valid
358
+ if (typeof result === 'number' && !isNaN(result) && isFinite(result)) {
359
+ // Round to reasonable precision
360
+ if (Math.abs(result - Math.round(result)) < 1e-10) {
361
+ return Math.round(result);
362
+ }
363
+ return Math.round(result * 1e10) / 1e10;
364
+ }
365
+
366
+ return null;
367
+ } catch (e) {
368
+ return null;
369
+ }
370
+ }
371
+
237
372
  // Process query
238
373
  function processQuery(query, isPreview) {
239
374
  if (!isPreview) {
240
375
  ipcRenderer.send('process-query', query);
241
376
  } else {
242
- // Show preview for calculations
377
+ // Show live preview for calculations
243
378
  try {
244
- // Simple preview for math expressions
245
- if (/^[\d\s\+\-\*\/\(\)\.\^]+$/.test(query)) {
246
- showResult('Calculating...', 'Press Enter to execute', 'success');
379
+ // Try to evaluate the expression live
380
+ const result = evaluateMathExpression(query);
381
+
382
+ if (result !== null) {
383
+ // Show the live result immediately
384
+ showResult(`= ${result}`, 'Press Enter to copy to clipboard', 'success');
385
+ } else if (/^[\d\s\+\-\*\/\(\)\.\^×÷]+$/.test(query)) {
386
+ // It looks like a math expression but couldn't be evaluated yet
387
+ showResult('...', 'Keep typing or press Enter', 'success');
247
388
  }
248
389
  } catch (error) {
249
390
  // Ignore preview errors
@@ -251,17 +392,37 @@
251
392
  }
252
393
  }
253
394
 
254
- // Handle theme toggle
395
+ // Available themes
396
+ const themes = ['dark', 'light', 'midnight', 'forest', 'sunset', 'purple', 'neon', 'ocean'];
397
+ let currentThemeIndex = 0;
398
+
399
+ // Apply theme by name
400
+ function applyTheme(themeName) {
401
+ themes.forEach(t => document.body.classList.remove(t));
402
+ if (themeName && themes.includes(themeName)) {
403
+ document.body.classList.add(themeName);
404
+ currentThemeIndex = themes.indexOf(themeName);
405
+ }
406
+ }
407
+
408
+ // Handle theme toggle (cycle through themes)
255
409
  ipcRenderer.on('toggle-theme', () => {
256
- document.body.classList.toggle('dark');
410
+ currentThemeIndex = (currentThemeIndex + 1) % themes.length;
411
+ applyTheme(themes[currentThemeIndex]);
257
412
  });
258
413
 
259
414
  // Handle result from main process
260
415
  ipcRenderer.on('query-result', (event, result) => {
261
416
  if (result.error) {
262
417
  showResult(`✗ ${result.error}`, '', 'error');
418
+ } else if (result.type === 'theme') {
419
+ // Apply the theme and show success
420
+ applyTheme(result.themeId);
421
+ showResult(`✓ ${result.formatted}`, '', 'success');
263
422
  } else if (result.type === 'system_command') {
264
- showResult(`✓ ${result.formatted}`, 'Copied to clipboard', 'system');
423
+ showResult(`✓ ${result.formatted}`, '', 'system');
424
+ } else if (result.type === 'info') {
425
+ showResult(`ℹ️ ${result.formatted}`, '', 'success');
265
426
  } else {
266
427
  showResult(`✓ ${result.formatted}`, 'Copied to clipboard', 'success');
267
428
  }
@@ -273,6 +434,12 @@
273
434
  resultText.className = `result-text ${type}`;
274
435
  resultHint.textContent = hint;
275
436
  resultContainer.classList.add('show');
437
+
438
+ // Calculate new height
439
+ setTimeout(() => {
440
+ const height = document.body.offsetHeight;
441
+ ipcRenderer.send('resize-window', height);
442
+ }, 10);
276
443
  }
277
444
 
278
445
  // Auto-focus on load