@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.
- package/BUILD_AND_RELEASE.md +75 -0
- package/LICENSE +654 -0
- package/README.md +165 -0
- package/assets/Agent_Mint.png +0 -0
- package/assets/CLI_Screen.png +0 -0
- package/assets/Settings.png +0 -0
- package/assets/icon.png +0 -0
- package/benchmark_ai.js +71 -0
- package/main.js +968 -0
- package/mint-cli-logic.js +71 -0
- package/mint-cli.js +239 -0
- package/package.json +60 -0
- package/preload-picker.js +11 -0
- package/preload-settings.js +11 -0
- package/preload.js +37 -0
- package/privacy.txt +1 -0
- package/src/AI_Brain/Gemini_API.js +419 -0
- package/src/AI_Brain/autonomous_brain.js +139 -0
- package/src/AI_Brain/behavior_memory.js +114 -0
- package/src/AI_Brain/headless_agent.js +120 -0
- package/src/AI_Brain/knowledge_base.js +222 -0
- package/src/AI_Brain/proactive_engine.js +168 -0
- package/src/Automation_Layer/browser_automation.js +147 -0
- package/src/Automation_Layer/file_operations.js +80 -0
- package/src/Automation_Layer/open_app.js +56 -0
- package/src/Automation_Layer/open_website.js +38 -0
- package/src/CLI/chat_ui.js +468 -0
- package/src/CLI/list_features.js +56 -0
- package/src/CLI/onboarding.js +60 -0
- package/src/Command_Parser/parser.js +34 -0
- package/src/Plugins/dev_tools.js +41 -0
- package/src/Plugins/discord.js +20 -0
- package/src/Plugins/docker.js +45 -0
- package/src/Plugins/google_calendar.js +26 -0
- package/src/Plugins/obsidian.js +54 -0
- package/src/Plugins/plugin_manager.js +81 -0
- package/src/Plugins/spotify.js +45 -0
- package/src/Plugins/system_metrics.js +31 -0
- package/src/System/chat_history_manager.js +57 -0
- package/src/System/config_manager.js +73 -0
- package/src/System/custom_workflows.js +127 -0
- package/src/System/daemon_manager.js +67 -0
- package/src/System/system_automation.js +88 -0
- package/src/System/system_events.js +79 -0
- package/src/System/system_info.js +55 -0
- package/src/System/task_manager.js +85 -0
- package/src/UI/floating.css +80 -0
- package/src/UI/floating.html +17 -0
- package/src/UI/floating.js +67 -0
- package/src/UI/index.html +126 -0
- package/src/UI/preload-floating.js +7 -0
- package/src/UI/preload-spotlight.js +10 -0
- package/src/UI/preload-widget.js +5 -0
- package/src/UI/proactive-glow.html +42 -0
- package/src/UI/renderer.js +978 -0
- package/src/UI/screenPicker.html +214 -0
- package/src/UI/screenPicker.js +262 -0
- package/src/UI/settings.css +705 -0
- package/src/UI/settings.html +396 -0
- package/src/UI/settings.js +514 -0
- package/src/UI/spotlight.css +119 -0
- package/src/UI/spotlight.html +23 -0
- package/src/UI/spotlight.js +181 -0
- package/src/UI/styles.css +627 -0
- package/src/UI/widget.css +218 -0
- package/src/UI/widget.html +29 -0
- package/src/UI/widget.js +10 -0
- package/tech_news.txt +3 -0
- package/test_knowledge.txt +3 -0
|
@@ -0,0 +1,214 @@
|
|
|
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>Screen Vision Picker</title>
|
|
7
|
+
<style>
|
|
8
|
+
body, html {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
width: 100vw;
|
|
12
|
+
height: 100vh;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
background: transparent;
|
|
15
|
+
cursor: crosshair;
|
|
16
|
+
user-select: none;
|
|
17
|
+
font-family: 'Inter', sans-serif;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#bg-canvas {
|
|
21
|
+
position: absolute;
|
|
22
|
+
top: 0;
|
|
23
|
+
left: 0;
|
|
24
|
+
z-index: 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#overlay-canvas {
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 0;
|
|
30
|
+
left: 0;
|
|
31
|
+
z-index: 2;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#toolbar {
|
|
35
|
+
position: absolute;
|
|
36
|
+
top: 20px;
|
|
37
|
+
left: 50%;
|
|
38
|
+
transform: translateX(-50%);
|
|
39
|
+
z-index: 10;
|
|
40
|
+
background: rgba(30, 30, 30, 0.9);
|
|
41
|
+
backdrop-filter: blur(10px);
|
|
42
|
+
padding: 10px 20px;
|
|
43
|
+
border-radius: 8px;
|
|
44
|
+
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
|
|
45
|
+
display: flex;
|
|
46
|
+
gap: 10px;
|
|
47
|
+
color: white;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.btn {
|
|
52
|
+
background: #2a2a2a;
|
|
53
|
+
color: #ccc;
|
|
54
|
+
border: 1px solid #444;
|
|
55
|
+
padding: 8px 16px;
|
|
56
|
+
border-radius: 6px;
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
transition: all 0.2s;
|
|
59
|
+
font-size: 14px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.btn:hover {
|
|
63
|
+
background: #3a3a3a;
|
|
64
|
+
color: white;
|
|
65
|
+
border-color: #666;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.btn-primary {
|
|
69
|
+
background: #28a745;
|
|
70
|
+
color: white;
|
|
71
|
+
border-color: #28a745;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.btn-primary:hover {
|
|
75
|
+
background: #218838;
|
|
76
|
+
border-color: #1e7e34;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.btn-danger {
|
|
80
|
+
background: #dc3545;
|
|
81
|
+
color: white;
|
|
82
|
+
border-color: #dc3545;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.btn-danger:hover {
|
|
86
|
+
background: #c82333;
|
|
87
|
+
border-color: #bd2130;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.btn-translate {
|
|
91
|
+
background: #8b5cf6;
|
|
92
|
+
color: white;
|
|
93
|
+
border-color: #7c3aed;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.btn-translate:hover {
|
|
97
|
+
background: #7c3aed;
|
|
98
|
+
border-color: #6d28d9;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.btn.active {
|
|
102
|
+
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.5);
|
|
103
|
+
transform: scale(0.95);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.hint {
|
|
107
|
+
font-size: 12px;
|
|
108
|
+
color: #aaa;
|
|
109
|
+
margin-right: 15px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Floating Translation Box */
|
|
113
|
+
#translation-box {
|
|
114
|
+
position: absolute;
|
|
115
|
+
background: rgba(20, 20, 20, 0.95);
|
|
116
|
+
backdrop-filter: blur(10px);
|
|
117
|
+
border: 1px solid #444;
|
|
118
|
+
color: #fff;
|
|
119
|
+
padding: 12px 16px;
|
|
120
|
+
border-radius: 8px;
|
|
121
|
+
font-family: 'Inter', sans-serif;
|
|
122
|
+
font-size: 14px;
|
|
123
|
+
line-height: 1.5;
|
|
124
|
+
box-shadow: 0 8px 25px rgba(0,0,0,0.6);
|
|
125
|
+
z-index: 100;
|
|
126
|
+
max-width: 400px;
|
|
127
|
+
display: none;
|
|
128
|
+
pointer-events: auto; /* Allow text selection */
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#translation-box.interactive {
|
|
132
|
+
pointer-events: auto;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.loading-spinner {
|
|
136
|
+
display: inline-block;
|
|
137
|
+
width: 16px;
|
|
138
|
+
height: 16px;
|
|
139
|
+
border: 2px solid rgba(255,255,255,0.3);
|
|
140
|
+
border-radius: 50%;
|
|
141
|
+
border-top-color: #fff;
|
|
142
|
+
animation: spin 1s ease-in-out infinite;
|
|
143
|
+
vertical-align: middle;
|
|
144
|
+
margin-right: 8px;
|
|
145
|
+
}
|
|
146
|
+
@keyframes spin {
|
|
147
|
+
to { transform: rotate(360deg); }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Close Button inside Translation Box */
|
|
151
|
+
.close-translate-btn {
|
|
152
|
+
position: absolute;
|
|
153
|
+
top: -18px;
|
|
154
|
+
right: -14px;
|
|
155
|
+
background: #dc3545;
|
|
156
|
+
color: white;
|
|
157
|
+
border: 2px solid rgba(20, 20, 20, 0.95);
|
|
158
|
+
border-radius: 999px;
|
|
159
|
+
min-width: 40px;
|
|
160
|
+
height: 24px;
|
|
161
|
+
padding: 0 8px;
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
justify-content: center;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
font-size: 12px;
|
|
167
|
+
font-weight: bold;
|
|
168
|
+
letter-spacing: 0.04em;
|
|
169
|
+
text-transform: uppercase;
|
|
170
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.5);
|
|
171
|
+
pointer-events: auto;
|
|
172
|
+
transition: background 0.2s;
|
|
173
|
+
}
|
|
174
|
+
.close-translate-btn:hover {
|
|
175
|
+
background: #c82333;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Vision Enhancements */
|
|
179
|
+
.vision-glow {
|
|
180
|
+
position: absolute;
|
|
181
|
+
inset: 0;
|
|
182
|
+
pointer-events: none;
|
|
183
|
+
box-shadow: inset 0 0 100px rgba(139, 92, 246, 0.15);
|
|
184
|
+
z-index: 5;
|
|
185
|
+
animation: vision-pulse 4s ease-in-out infinite alternate;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@keyframes vision-pulse {
|
|
189
|
+
from { box-shadow: inset 0 0 60px rgba(139, 92, 246, 0.1); }
|
|
190
|
+
to { box-shadow: inset 0 0 120px rgba(139, 92, 246, 0.25); }
|
|
191
|
+
}
|
|
192
|
+
</style>
|
|
193
|
+
</head>
|
|
194
|
+
<body>
|
|
195
|
+
<div class="vision-glow"></div>
|
|
196
|
+
<div id="toolbar">
|
|
197
|
+
<span class="hint" id="hint-text">Click and drag to select a region</span>
|
|
198
|
+
<button class="btn btn-translate" id="btn-translate">🌐 Live Translate</button>
|
|
199
|
+
<button class="btn btn-primary" id="btn-fullscreen">Full Screen</button>
|
|
200
|
+
<button class="btn btn-danger" id="btn-cancel">Cancel</button>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<canvas id="bg-canvas"></canvas>
|
|
204
|
+
<canvas id="overlay-canvas"></canvas>
|
|
205
|
+
|
|
206
|
+
<!-- Translation Results Wrapper -->
|
|
207
|
+
<div id="translation-box">
|
|
208
|
+
<div class="close-translate-btn" id="btn-close-translate">Esc</div>
|
|
209
|
+
<div id="translation-content"></div>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<script src="screenPicker.js"></script>
|
|
213
|
+
</body>
|
|
214
|
+
</html>
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
const bgCanvas = document.getElementById('bg-canvas');
|
|
2
|
+
const overlayCanvas = document.getElementById('overlay-canvas');
|
|
3
|
+
const bgCtx = bgCanvas.getContext('2d');
|
|
4
|
+
const overlayCtx = overlayCanvas.getContext('2d');
|
|
5
|
+
|
|
6
|
+
let isDrawing = false;
|
|
7
|
+
let startX = 0;
|
|
8
|
+
let startY = 0;
|
|
9
|
+
let currentX = 0;
|
|
10
|
+
let currentY = 0;
|
|
11
|
+
let baseImage = null;
|
|
12
|
+
let selectedRect = null;
|
|
13
|
+
let isOverlayInteractable = true;
|
|
14
|
+
|
|
15
|
+
let isTranslateMode = false;
|
|
16
|
+
let isContinuousTranslateActive = false;
|
|
17
|
+
const translateBtn = document.getElementById('btn-translate');
|
|
18
|
+
const hintText = document.getElementById('hint-text');
|
|
19
|
+
const translationBox = document.getElementById('translation-box');
|
|
20
|
+
const translationContent = document.getElementById('translation-content');
|
|
21
|
+
const btnCloseTranslate = document.getElementById('btn-close-translate');
|
|
22
|
+
const toolbar = document.getElementById('toolbar');
|
|
23
|
+
|
|
24
|
+
// Initialize canvases
|
|
25
|
+
function init() {
|
|
26
|
+
bgCanvas.width = window.innerWidth;
|
|
27
|
+
bgCanvas.height = window.innerHeight;
|
|
28
|
+
overlayCanvas.width = window.innerWidth;
|
|
29
|
+
overlayCanvas.height = window.innerHeight;
|
|
30
|
+
|
|
31
|
+
// Wait for the main process to send the screenshot
|
|
32
|
+
window.electronPicker.onScreenshot((base64Data) => {
|
|
33
|
+
baseImage = new Image();
|
|
34
|
+
baseImage.onload = () => {
|
|
35
|
+
bgCtx.drawImage(baseImage, 0, 0, bgCanvas.width, bgCanvas.height);
|
|
36
|
+
drawDarkOverlay();
|
|
37
|
+
};
|
|
38
|
+
baseImage.src = base64Data;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function drawDarkOverlay() {
|
|
43
|
+
overlayCtx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
|
44
|
+
overlayCtx.fillStyle = 'rgba(0, 0, 0, 0.5)';
|
|
45
|
+
overlayCtx.fillRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function normalizeRect(rect) {
|
|
49
|
+
return {
|
|
50
|
+
x: Math.min(rect.startX, rect.currentX),
|
|
51
|
+
y: Math.min(rect.startY, rect.currentY),
|
|
52
|
+
width: Math.abs(rect.width),
|
|
53
|
+
height: Math.abs(rect.height)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function drawSelectionOutline(rect) {
|
|
58
|
+
if (!rect || rect.width === 0 || rect.height === 0) return;
|
|
59
|
+
|
|
60
|
+
overlayCtx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
|
61
|
+
overlayCtx.strokeStyle = isTranslateMode ? '#8b5cf6' : '#00ff88';
|
|
62
|
+
overlayCtx.lineWidth = 3;
|
|
63
|
+
overlayCtx.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function drawSelection() {
|
|
67
|
+
drawDarkOverlay();
|
|
68
|
+
|
|
69
|
+
const rect = normalizeRect({
|
|
70
|
+
startX,
|
|
71
|
+
startY,
|
|
72
|
+
currentX,
|
|
73
|
+
currentY,
|
|
74
|
+
width: currentX - startX,
|
|
75
|
+
height: currentY - startY
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
overlayCtx.clearRect(rect.x, rect.y, rect.width, rect.height);
|
|
79
|
+
overlayCtx.strokeStyle = isTranslateMode ? '#8b5cf6' : '#00ff88';
|
|
80
|
+
overlayCtx.lineWidth = 2;
|
|
81
|
+
overlayCtx.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resetSelectionOverlay() {
|
|
85
|
+
selectedRect = null;
|
|
86
|
+
overlayCanvas.style.pointerEvents = 'auto';
|
|
87
|
+
isOverlayInteractable = true;
|
|
88
|
+
drawDarkOverlay();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function setOverlayInteractable(isInteractable) {
|
|
92
|
+
if (isOverlayInteractable === isInteractable) return;
|
|
93
|
+
isOverlayInteractable = isInteractable;
|
|
94
|
+
window.electronPicker.setOverlayInteractable(isInteractable);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function stopTranslationMode({ keepTranslateMode = false } = {}) {
|
|
98
|
+
isContinuousTranslateActive = false;
|
|
99
|
+
isTranslateMode = keepTranslateMode;
|
|
100
|
+
|
|
101
|
+
translationBox.style.display = 'none';
|
|
102
|
+
toolbar.style.display = 'flex';
|
|
103
|
+
overlayCanvas.style.pointerEvents = 'auto';
|
|
104
|
+
translateBtn.classList.toggle('active', keepTranslateMode);
|
|
105
|
+
translateBtn.innerText = keepTranslateMode ? 'Stop Translate' : '🌐 Live Translate';
|
|
106
|
+
hintText.innerText = keepTranslateMode ? 'Drag over text to translate to Thai' : 'Click and drag to select a region';
|
|
107
|
+
|
|
108
|
+
window.electronPicker.stopContinuousTranslation();
|
|
109
|
+
setOverlayInteractable(true);
|
|
110
|
+
|
|
111
|
+
if (baseImage) {
|
|
112
|
+
bgCtx.clearRect(0, 0, bgCanvas.width, bgCanvas.height);
|
|
113
|
+
bgCtx.drawImage(baseImage, 0, 0, bgCanvas.width, bgCanvas.height);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resetSelectionOverlay();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function setTranslationBoxPosition(rect) {
|
|
120
|
+
const margin = 10;
|
|
121
|
+
const boxWidth = Math.min(400, Math.max(240, rect.width));
|
|
122
|
+
translationBox.style.maxWidth = `${boxWidth}px`;
|
|
123
|
+
translationBox.style.left = `${Math.max(margin, Math.min(rect.x, window.innerWidth - boxWidth - margin))}px`;
|
|
124
|
+
|
|
125
|
+
const preferredTop = rect.y + rect.height + margin;
|
|
126
|
+
const fallbackTop = Math.max(margin, rect.y - margin - translationBox.offsetHeight);
|
|
127
|
+
const top = preferredTop + translationBox.offsetHeight <= window.innerHeight
|
|
128
|
+
? preferredTop
|
|
129
|
+
: fallbackTop;
|
|
130
|
+
|
|
131
|
+
translationBox.style.top = `${top}px`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function cropAndSend(rect) {
|
|
135
|
+
if (rect.width === 0 || rect.height === 0) return;
|
|
136
|
+
|
|
137
|
+
const { x, y, width: w, height: h } = normalizeRect(rect);
|
|
138
|
+
|
|
139
|
+
const cropCanvas = document.createElement('canvas');
|
|
140
|
+
cropCanvas.width = w;
|
|
141
|
+
cropCanvas.height = h;
|
|
142
|
+
const cropCtx = cropCanvas.getContext('2d');
|
|
143
|
+
|
|
144
|
+
cropCtx.drawImage(
|
|
145
|
+
baseImage,
|
|
146
|
+
x, y, w, h,
|
|
147
|
+
0, 0, w, h
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const croppedBase64 = cropCanvas.toDataURL('image/png');
|
|
151
|
+
|
|
152
|
+
if (isTranslateMode) {
|
|
153
|
+
isContinuousTranslateActive = true;
|
|
154
|
+
selectedRect = { x, y, width: w, height: h };
|
|
155
|
+
|
|
156
|
+
toolbar.style.display = 'none';
|
|
157
|
+
bgCtx.clearRect(0, 0, bgCanvas.width, bgCanvas.height);
|
|
158
|
+
overlayCanvas.style.pointerEvents = 'none';
|
|
159
|
+
drawSelectionOutline(selectedRect);
|
|
160
|
+
|
|
161
|
+
translationBox.style.display = 'block';
|
|
162
|
+
translationContent.innerHTML = '<span class="loading-spinner"></span> Auto-Translating...';
|
|
163
|
+
setTranslationBoxPosition(selectedRect);
|
|
164
|
+
setOverlayInteractable(false);
|
|
165
|
+
|
|
166
|
+
window.electronPicker.startContinuousTranslation({ x, y, width: w, height: h });
|
|
167
|
+
} else {
|
|
168
|
+
window.electronPicker.sendSelection(croppedBase64);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Listen for continuous translation results from main process
|
|
173
|
+
window.electronPicker.onTranslationResult((thaiText) => {
|
|
174
|
+
if (isContinuousTranslateActive && translationBox.style.display === 'block') {
|
|
175
|
+
translationContent.innerHTML = thaiText;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Stop continuous translation
|
|
180
|
+
btnCloseTranslate.addEventListener('click', (e) => {
|
|
181
|
+
e.stopPropagation();
|
|
182
|
+
stopTranslationMode();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
window.addEventListener('keydown', (e) => {
|
|
186
|
+
if (e.key !== 'Escape' || !isContinuousTranslateActive) return;
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
stopTranslationMode();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
window.addEventListener('mousemove', (e) => {
|
|
192
|
+
if (!isContinuousTranslateActive || translationBox.style.display !== 'block') return;
|
|
193
|
+
|
|
194
|
+
const rect = translationBox.getBoundingClientRect();
|
|
195
|
+
const isInsideBox = e.clientX >= rect.left
|
|
196
|
+
&& e.clientX <= rect.right
|
|
197
|
+
&& e.clientY >= rect.top
|
|
198
|
+
&& e.clientY <= rect.bottom;
|
|
199
|
+
|
|
200
|
+
setOverlayInteractable(isInsideBox);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Mouse Events
|
|
204
|
+
overlayCanvas.addEventListener('mousedown', (e) => {
|
|
205
|
+
if (isContinuousTranslateActive) return;
|
|
206
|
+
isDrawing = true;
|
|
207
|
+
startX = e.clientX;
|
|
208
|
+
startY = e.clientY;
|
|
209
|
+
currentX = e.clientX;
|
|
210
|
+
currentY = e.clientY;
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
overlayCanvas.addEventListener('mousemove', (e) => {
|
|
214
|
+
if (!isDrawing) return;
|
|
215
|
+
currentX = e.clientX;
|
|
216
|
+
currentY = e.clientY;
|
|
217
|
+
drawSelection();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
overlayCanvas.addEventListener('mouseup', (e) => {
|
|
221
|
+
if (!isDrawing) return;
|
|
222
|
+
currentX = e.clientX;
|
|
223
|
+
currentY = e.clientY;
|
|
224
|
+
isDrawing = false;
|
|
225
|
+
cropAndSend({ startX, startY, currentX, currentY, width: currentX - startX, height: currentY - startY });
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// UI Buttons
|
|
229
|
+
translateBtn.addEventListener('click', () => {
|
|
230
|
+
isTranslateMode = !isTranslateMode;
|
|
231
|
+
if (isTranslateMode) {
|
|
232
|
+
translateBtn.classList.add('active');
|
|
233
|
+
translateBtn.innerText = 'Stop Translate';
|
|
234
|
+
hintText.innerText = 'Drag over text to translate to Thai';
|
|
235
|
+
translationBox.style.display = 'none';
|
|
236
|
+
resetSelectionOverlay();
|
|
237
|
+
} else {
|
|
238
|
+
if (isContinuousTranslateActive) {
|
|
239
|
+
stopTranslationMode();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
translateBtn.classList.remove('active');
|
|
243
|
+
translateBtn.innerText = '🌐 Live Translate';
|
|
244
|
+
hintText.innerText = 'Click and drag to select a region';
|
|
245
|
+
translationBox.style.display = 'none';
|
|
246
|
+
resetSelectionOverlay();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
document.getElementById('btn-fullscreen').addEventListener('click', () => {
|
|
251
|
+
if (baseImage && !isTranslateMode) {
|
|
252
|
+
window.electronPicker.sendSelection(baseImage.src);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
document.getElementById('btn-cancel').addEventListener('click', () => {
|
|
257
|
+
window.electronPicker.closePicker();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Setup
|
|
261
|
+
window.addEventListener('resize', init);
|
|
262
|
+
init();
|