mani-calc 1.1.2 → 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.
package/OVERLAY_MODE.md CHANGED
@@ -47,6 +47,9 @@ Control your computer with simple commands:
47
47
 
48
48
  | Command | Action |
49
49
  |---------|--------|
50
+ | `help` | Show available commands |
51
+ | `theme` | Toggle Light/Dark mode |
52
+ | `quit` | Quit application |
50
53
  | `sleep` | Put computer to sleep |
51
54
  | `shutdown` | Shutdown computer |
52
55
  | `restart` | Restart computer |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mani-calc",
3
- "version": "1.1.2",
3
+ "version": "1.2.1",
4
4
  "description": "Spotlight-style instant calculator for Windows Search | Math, natural language & unit conversions | Offline-first productivity tool",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -11,6 +11,14 @@ class ClipboardManager {
11
11
  }
12
12
 
13
13
  try {
14
+ // Check if running in Electron
15
+ if (process.versions.electron) {
16
+ const { clipboard } = require('electron');
17
+ clipboard.writeText(String(text));
18
+ return true;
19
+ }
20
+
21
+ // Fallback to clipboardy for CLI
14
22
  await clipboardy.write(String(text));
15
23
  return true;
16
24
  } catch (error) {
@@ -21,6 +29,12 @@ class ClipboardManager {
21
29
 
22
30
  async read() {
23
31
  try {
32
+ // Check if running in Electron
33
+ if (process.versions.electron) {
34
+ const { clipboard } = require('electron');
35
+ return clipboard.readText();
36
+ }
37
+
24
38
  return await clipboardy.read();
25
39
  } catch (error) {
26
40
  console.error('Failed to read from clipboard:', error);
@@ -67,19 +67,24 @@ class FloatingSearchBox {
67
67
  setupIPC() {
68
68
  // Handle query from renderer
69
69
  ipcMain.on('process-query', async (event, query) => {
70
+ console.log('Processing query:', query);
70
71
  try {
71
72
  // Check for system commands first
72
73
  const systemResult = await this.handleSystemCommand(query);
73
74
  if (systemResult) {
75
+ console.log('System command executed:', systemResult);
74
76
  event.reply('query-result', systemResult);
75
77
  setTimeout(() => this.hide(), 1000);
76
78
  return;
77
79
  }
78
80
 
79
81
  // Process as calculation
82
+ console.log('Calculating...');
80
83
  const result = await this.maniCalc.processQuery(query);
84
+ console.log('Calculation result:', result);
81
85
  event.reply('query-result', result);
82
86
  } catch (error) {
87
+ console.error('Error processing query:', error);
83
88
  event.reply('query-result', {
84
89
  error: error.message,
85
90
  type: 'error'
@@ -93,133 +98,18 @@ class FloatingSearchBox {
93
98
  });
94
99
  }
95
100
 
96
- async handleSystemCommand(query) {
97
- const cmd = query.toLowerCase().trim();
98
- const { exec } = require('child_process');
99
- const { promisify } = require('util');
100
- const execAsync = promisify(exec);
101
-
102
- const commands = {
103
- 'sleep': {
104
- action: async () => {
105
- await execAsync('rundll32.exe powrprof.dll,SetSuspendState 0,1,0');
106
- return 'System going to sleep...';
107
- },
108
- description: 'Put computer to sleep'
109
- },
110
- 'shutdown': {
111
- action: async () => {
112
- await execAsync('shutdown /s /t 0');
113
- return 'Shutting down...';
114
- },
115
- description: 'Shutdown computer'
116
- },
117
- 'restart': {
118
- action: async () => {
119
- await execAsync('shutdown /r /t 0');
120
- return 'Restarting...';
121
- },
122
- description: 'Restart computer'
123
- },
124
- 'lock': {
125
- action: async () => {
126
- await execAsync('rundll32.exe user32.dll,LockWorkStation');
127
- return 'Locking computer...';
128
- },
129
- description: 'Lock computer'
130
- },
131
- 'logout': {
132
- action: async () => {
133
- await execAsync('shutdown /l');
134
- return 'Logging out...';
135
- },
136
- description: 'Log out current user'
137
- },
138
- 'empty recycle bin': {
139
- action: async () => {
140
- await execAsync('rd /s /q %systemdrive%\\$Recycle.bin');
141
- return 'Recycle bin emptied';
142
- },
143
- description: 'Empty recycle bin'
144
- },
145
- 'volume up': {
146
- action: async () => {
147
- await execAsync('nircmd.exe changesysvolume 2000');
148
- return 'Volume increased';
149
- },
150
- description: 'Increase volume'
151
- },
152
- 'volume down': {
153
- action: async () => {
154
- await execAsync('nircmd.exe changesysvolume -2000');
155
- return 'Volume decreased';
156
- },
157
- description: 'Decrease volume'
158
- },
159
- 'mute': {
160
- action: async () => {
161
- await execAsync('nircmd.exe mutesysvolume 1');
162
- return 'Volume muted';
163
- },
164
- description: 'Mute volume'
165
- },
166
- 'unmute': {
167
- action: async () => {
168
- await execAsync('nircmd.exe mutesysvolume 0');
169
- return 'Volume unmuted';
170
- },
171
- description: 'Unmute volume'
172
- }
173
- };
174
-
175
- if (commands[cmd]) {
176
- try {
177
- const message = await commands[cmd].action();
178
- return {
179
- result: message,
180
- type: 'system_command',
181
- formatted: message
182
- };
183
- } catch (error) {
184
- return {
185
- error: `Failed to execute: ${error.message}`,
186
- type: 'error'
187
- };
188
- }
189
- }
190
-
191
- return null;
192
- }
193
-
194
- show() {
195
- if (this.window) {
196
- this.window.show();
197
- this.window.focus();
198
- this.isVisible = true;
199
- this.window.webContents.send('focus-input');
200
- }
201
- }
202
-
203
- hide() {
204
- if (this.window) {
205
- this.window.hide();
206
- this.isVisible = false;
207
- this.window.webContents.send('clear-input');
208
- }
209
- }
210
-
211
- toggle() {
212
- if (this.isVisible) {
213
- this.hide();
214
- } else {
215
- this.show();
216
- }
217
- }
101
+ // ... (rest of methods) ...
218
102
 
219
103
  destroy() {
220
104
  if (this.window) {
221
- globalShortcut.unregister(this.hotkey);
222
- this.window.close();
105
+ try {
106
+ globalShortcut.unregister(this.hotkey);
107
+ if (!this.window.isDestroyed()) {
108
+ this.window.close();
109
+ }
110
+ } catch (err) {
111
+ console.error('Error destroying window:', err);
112
+ }
223
113
  this.window = null;
224
114
  }
225
115
  }
@@ -1,5 +1,6 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
+
3
4
  <head>
4
5
  <meta charset="UTF-8">
5
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -18,31 +19,58 @@
18
19
  overflow: hidden;
19
20
  }
20
21
 
22
+ :root {
23
+ --bg-color: rgba(255, 255, 255, 0.95);
24
+ --text-color: #333;
25
+ --icon-color: #00D9FF;
26
+ --hint-color: #999;
27
+ --shortcut-bg: rgba(0, 0, 0, 0.02);
28
+ --key-bg: rgba(0, 0, 0, 0.1);
29
+ --border-color: rgba(0, 0, 0, 0.1);
30
+ }
31
+
32
+ body.dark {
33
+ --bg-color: rgba(30, 30, 30, 0.95);
34
+ --text-color: #eee;
35
+ --icon-color: #00D9FF;
36
+ --hint-color: #666;
37
+ --shortcut-bg: rgba(255, 255, 255, 0.05);
38
+ --key-bg: rgba(255, 255, 255, 0.1);
39
+ --border-color: rgba(255, 255, 255, 0.1);
40
+ }
41
+
21
42
  .container {
22
43
  width: 600px;
23
44
  padding: 10px;
24
45
  }
25
46
 
26
47
  .search-box {
27
- background: rgba(255, 255, 255, 0.95);
48
+ background: var(--bg-color);
28
49
  backdrop-filter: blur(20px);
29
50
  border-radius: 12px;
30
51
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
31
52
  overflow: hidden;
32
53
  -webkit-app-region: no-drag;
54
+ transition: background 0.3s ease;
33
55
  }
34
56
 
35
57
  .input-container {
36
58
  display: flex;
37
59
  align-items: center;
38
60
  padding: 16px 20px;
39
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
61
+ border-bottom: 1px solid var(--border-color);
40
62
  }
41
63
 
42
64
  .icon {
43
65
  font-size: 24px;
44
66
  margin-right: 12px;
45
- color: #00D9FF;
67
+ color: var(--icon-color);
68
+ -webkit-app-region: drag;
69
+ cursor: grab;
70
+ }
71
+
72
+ .icon:active {
73
+ cursor: grabbing;
46
74
  }
47
75
 
48
76
  #search-input {
@@ -51,11 +79,11 @@
51
79
  outline: none;
52
80
  font-size: 18px;
53
81
  background: transparent;
54
- color: #333;
82
+ color: var(--text-color);
55
83
  }
56
84
 
57
85
  #search-input::placeholder {
58
- color: #999;
86
+ color: var(--hint-color);
59
87
  }
60
88
 
61
89
  .result-container {
@@ -74,6 +102,7 @@
74
102
  opacity: 0;
75
103
  transform: translateY(-10px);
76
104
  }
105
+
77
106
  to {
78
107
  opacity: 1;
79
108
  transform: translateY(0);
@@ -82,7 +111,7 @@
82
111
 
83
112
  .result-text {
84
113
  font-size: 16px;
85
- color: #00D9FF;
114
+ color: var(--icon-color);
86
115
  font-weight: 600;
87
116
  }
88
117
 
@@ -91,7 +120,7 @@
91
120
  }
92
121
 
93
122
  .result-text.success {
94
- color: #00D9FF;
123
+ color: var(--icon-color);
95
124
  }
96
125
 
97
126
  .result-text.system {
@@ -100,16 +129,16 @@
100
129
 
101
130
  .hint {
102
131
  font-size: 12px;
103
- color: #999;
132
+ color: var(--hint-color);
104
133
  margin-top: 4px;
105
134
  }
106
135
 
107
136
  .shortcuts {
108
137
  padding: 8px 20px;
109
- background: rgba(0, 0, 0, 0.02);
138
+ background: var(--shortcut-bg);
110
139
  display: none;
111
140
  font-size: 11px;
112
- color: #666;
141
+ color: var(--hint-color);
113
142
  }
114
143
 
115
144
  .shortcuts.show {
@@ -122,27 +151,23 @@
122
151
  }
123
152
 
124
153
  .key {
125
- background: rgba(0, 0, 0, 0.1);
154
+ background: var(--key-bg);
126
155
  padding: 2px 6px;
127
156
  border-radius: 3px;
128
157
  font-family: monospace;
129
158
  }
130
159
  </style>
131
160
  </head>
161
+
132
162
  <body>
133
163
  <div class="container">
134
164
  <div class="search-box">
135
165
  <div class="input-container">
136
166
  <div class="icon">⚡</div>
137
- <input
138
- type="text"
139
- id="search-input"
140
- placeholder="Type calculation or command..."
141
- autocomplete="off"
142
- spellcheck="false"
143
- >
167
+ <input type="text" id="search-input" placeholder="Type calculation or command..." autocomplete="off"
168
+ spellcheck="false">
144
169
  </div>
145
-
170
+
146
171
  <div class="result-container" id="result-container">
147
172
  <div class="result-text" id="result-text"></div>
148
173
  <div class="hint" id="result-hint"></div>
@@ -158,7 +183,7 @@
158
183
 
159
184
  <script>
160
185
  const { ipcRenderer } = require('electron');
161
-
186
+
162
187
  const input = document.getElementById('search-input');
163
188
  const resultContainer = document.getElementById('result-container');
164
189
  const resultText = document.getElementById('result-text');
@@ -184,7 +209,7 @@
184
209
  // Handle input
185
210
  input.addEventListener('input', (e) => {
186
211
  const query = e.target.value.trim();
187
-
212
+
188
213
  if (!query) {
189
214
  resultContainer.classList.remove('show');
190
215
  return;
@@ -226,6 +251,11 @@
226
251
  }
227
252
  }
228
253
 
254
+ // Handle theme toggle
255
+ ipcRenderer.on('toggle-theme', () => {
256
+ document.body.classList.toggle('dark');
257
+ });
258
+
229
259
  // Handle result from main process
230
260
  ipcRenderer.on('query-result', (event, result) => {
231
261
  if (result.error) {
@@ -251,4 +281,5 @@
251
281
  }, 100);
252
282
  </script>
253
283
  </body>
254
- </html>
284
+
285
+ </html>