pake-cli 3.5.3 → 3.6.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.
- package/README.md +17 -14
- package/dist/cli.js +9 -5
- package/package.json +1 -1
- package/src-tauri/Cargo.lock +52 -30
- package/src-tauri/Cargo.toml +10 -9
- package/src-tauri/gen/schemas/acl-manifests.json +1 -1
- package/src-tauri/gen/schemas/desktop-schema.json +233 -0
- package/src-tauri/gen/schemas/macOS-schema.json +233 -0
- package/src-tauri/src/app/invoke.rs +37 -0
- package/src-tauri/src/app/window.rs +44 -0
- package/src-tauri/src/inject/auth.js +75 -0
- package/src-tauri/src/inject/event.js +8 -1
- package/src-tauri/src/inject/theme_refresh.js +124 -0
- package/src-tauri/src/lib.rs +247 -2
- package/src-tauri/tauri.conf.json +2 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// OAuth and Authentication Logic
|
|
2
|
+
|
|
3
|
+
// Check if URL matches OAuth/authentication patterns
|
|
4
|
+
function matchesAuthUrl(url, baseUrl = window.location.href) {
|
|
5
|
+
try {
|
|
6
|
+
const urlObj = new URL(url, baseUrl);
|
|
7
|
+
const hostname = urlObj.hostname.toLowerCase();
|
|
8
|
+
const pathname = urlObj.pathname.toLowerCase();
|
|
9
|
+
const fullUrl = urlObj.href.toLowerCase();
|
|
10
|
+
|
|
11
|
+
// Common OAuth providers and paths
|
|
12
|
+
const oauthPatterns = [
|
|
13
|
+
/accounts\.google\.com/,
|
|
14
|
+
/accounts\.google\.[a-z]+/,
|
|
15
|
+
/login\.microsoftonline\.com/,
|
|
16
|
+
/github\.com\/login/,
|
|
17
|
+
/facebook\.com\/.*\/dialog/,
|
|
18
|
+
/twitter\.com\/oauth/,
|
|
19
|
+
/appleid\.apple\.com/,
|
|
20
|
+
/\/oauth\//,
|
|
21
|
+
/\/auth\//,
|
|
22
|
+
/\/authorize/,
|
|
23
|
+
/\/login\/oauth/,
|
|
24
|
+
/\/signin/,
|
|
25
|
+
/\/login/,
|
|
26
|
+
/servicelogin/,
|
|
27
|
+
/\/o\/oauth2/,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const isMatch = oauthPatterns.some(
|
|
31
|
+
(pattern) =>
|
|
32
|
+
pattern.test(hostname) ||
|
|
33
|
+
pattern.test(pathname) ||
|
|
34
|
+
pattern.test(fullUrl),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (isMatch) {
|
|
38
|
+
console.log("[Pake] OAuth URL detected:", url);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return isMatch;
|
|
42
|
+
} catch (e) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check if URL is an OAuth/authentication link
|
|
48
|
+
function isAuthLink(url) {
|
|
49
|
+
return matchesAuthUrl(url);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check if this is an OAuth/authentication popup
|
|
53
|
+
function isAuthPopup(url, name) {
|
|
54
|
+
// Check for known authentication window names
|
|
55
|
+
const authWindowNames = [
|
|
56
|
+
"AppleAuthentication",
|
|
57
|
+
"oauth2",
|
|
58
|
+
"oauth",
|
|
59
|
+
"google-auth",
|
|
60
|
+
"auth-popup",
|
|
61
|
+
"signin",
|
|
62
|
+
"login",
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
if (authWindowNames.includes(name)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return matchesAuthUrl(url);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Export functions to global scope
|
|
73
|
+
window.matchesAuthUrl = matchesAuthUrl;
|
|
74
|
+
window.isAuthLink = isAuthLink;
|
|
75
|
+
window.isAuthPopup = isAuthPopup;
|
|
@@ -394,6 +394,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
394
394
|
const absoluteUrl = hrefUrl.href;
|
|
395
395
|
let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl);
|
|
396
396
|
|
|
397
|
+
// Early check: Allow OAuth/authentication links to navigate naturally
|
|
398
|
+
if (window.isAuthLink(absoluteUrl)) {
|
|
399
|
+
console.log("[Pake] Allowing OAuth navigation to:", absoluteUrl);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
397
403
|
// Handle _blank links: same domain navigates in-app, cross-domain opens new window
|
|
398
404
|
if (target === "_blank") {
|
|
399
405
|
if (forceInternalNavigation) {
|
|
@@ -477,7 +483,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
477
483
|
// Rewrite the window.open function.
|
|
478
484
|
const originalWindowOpen = window.open;
|
|
479
485
|
window.open = function (url, name, specs) {
|
|
480
|
-
|
|
486
|
+
// Allow authentication popups to open normally
|
|
487
|
+
if (window.isAuthPopup(url, name)) {
|
|
481
488
|
return originalWindowOpen.call(window, url, name, specs);
|
|
482
489
|
}
|
|
483
490
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
2
|
+
// Helper: Calculate brightness from RGB color
|
|
3
|
+
const isDarkColor = (color) => {
|
|
4
|
+
if (!color) return false;
|
|
5
|
+
const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
6
|
+
if (!match) return false;
|
|
7
|
+
const r = parseInt(match[1]);
|
|
8
|
+
const g = parseInt(match[2]);
|
|
9
|
+
const b = parseInt(match[3]);
|
|
10
|
+
// Standard luminance formula
|
|
11
|
+
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
12
|
+
return luminance < 128;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Debounce helper
|
|
16
|
+
const debounce = (func, wait) => {
|
|
17
|
+
let timeout;
|
|
18
|
+
return function executedFunction(...args) {
|
|
19
|
+
const later = () => {
|
|
20
|
+
clearTimeout(timeout);
|
|
21
|
+
func(...args);
|
|
22
|
+
};
|
|
23
|
+
clearTimeout(timeout);
|
|
24
|
+
timeout = setTimeout(later, wait);
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Function to detect and send theme to Rust
|
|
29
|
+
const updateTheme = () => {
|
|
30
|
+
let mode = "light";
|
|
31
|
+
let detected = false;
|
|
32
|
+
|
|
33
|
+
// Strategy 1: Explicit DOM Class/Attribute (High Priority)
|
|
34
|
+
// Many apps use specific classes for hard-coded themes
|
|
35
|
+
const doc = document.documentElement;
|
|
36
|
+
const body = document.body;
|
|
37
|
+
|
|
38
|
+
const isExplicitDark =
|
|
39
|
+
doc.classList.contains("dark") ||
|
|
40
|
+
body.classList.contains("dark") ||
|
|
41
|
+
doc.getAttribute("data-theme") === "dark" ||
|
|
42
|
+
body.getAttribute("data-theme") === "dark" ||
|
|
43
|
+
doc.style.colorScheme === "dark";
|
|
44
|
+
|
|
45
|
+
const isExplicitLight =
|
|
46
|
+
doc.classList.contains("light") ||
|
|
47
|
+
body.classList.contains("light") ||
|
|
48
|
+
doc.getAttribute("data-theme") === "light" ||
|
|
49
|
+
body.getAttribute("data-theme") === "light" ||
|
|
50
|
+
doc.style.colorScheme === "light";
|
|
51
|
+
|
|
52
|
+
if (isExplicitDark) {
|
|
53
|
+
mode = "dark";
|
|
54
|
+
detected = true;
|
|
55
|
+
} else if (isExplicitLight) {
|
|
56
|
+
mode = "light";
|
|
57
|
+
detected = true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Strategy 2: Computed Background Color (Fallback & Verification)
|
|
61
|
+
// If no explicit class is found, or to double-check, look at the actual background color.
|
|
62
|
+
// This is useful when the site relies purely on CSS media queries without classes.
|
|
63
|
+
if (!detected) {
|
|
64
|
+
const bodyBg = window.getComputedStyle(document.body).backgroundColor;
|
|
65
|
+
const htmlBg = window.getComputedStyle(
|
|
66
|
+
document.documentElement,
|
|
67
|
+
).backgroundColor;
|
|
68
|
+
|
|
69
|
+
// Check body first, then html
|
|
70
|
+
if (bodyBg && bodyBg !== "rgba(0, 0, 0, 0)" && bodyBg !== "transparent") {
|
|
71
|
+
mode = isDarkColor(bodyBg) ? "dark" : "light";
|
|
72
|
+
} else if (
|
|
73
|
+
htmlBg &&
|
|
74
|
+
htmlBg !== "rgba(0, 0, 0, 0)" &&
|
|
75
|
+
htmlBg !== "transparent"
|
|
76
|
+
) {
|
|
77
|
+
mode = isDarkColor(htmlBg) ? "dark" : "light";
|
|
78
|
+
} else {
|
|
79
|
+
// Strategy 3: System Preference (Last Resort)
|
|
80
|
+
if (
|
|
81
|
+
window.matchMedia &&
|
|
82
|
+
window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
83
|
+
) {
|
|
84
|
+
mode = "dark";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Send to Rust
|
|
90
|
+
if (window.__TAURI__ && window.__TAURI__.core) {
|
|
91
|
+
window.__TAURI__.core.invoke("update_theme_mode", { mode });
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Debounced version of updateTheme
|
|
96
|
+
const debouncedUpdateTheme = debounce(updateTheme, 200);
|
|
97
|
+
|
|
98
|
+
// Initial check
|
|
99
|
+
// Delay slightly to ensure styles are applied
|
|
100
|
+
setTimeout(updateTheme, 100);
|
|
101
|
+
|
|
102
|
+
// Watch for system theme changes
|
|
103
|
+
window
|
|
104
|
+
.matchMedia("(prefers-color-scheme: dark)")
|
|
105
|
+
.addEventListener("change", updateTheme);
|
|
106
|
+
|
|
107
|
+
// Watch for DOM changes
|
|
108
|
+
// We observe attributes for class changes, and also style changes just in case
|
|
109
|
+
const observer = new MutationObserver((mutations) => {
|
|
110
|
+
debouncedUpdateTheme();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
observer.observe(document.documentElement, {
|
|
114
|
+
attributes: true,
|
|
115
|
+
attributeFilter: ["class", "data-theme", "style"],
|
|
116
|
+
subtree: false,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
observer.observe(document.body, {
|
|
120
|
+
attributes: true,
|
|
121
|
+
attributeFilter: ["class", "data-theme", "style"],
|
|
122
|
+
subtree: false,
|
|
123
|
+
});
|
|
124
|
+
});
|
package/src-tauri/src/lib.rs
CHANGED
|
@@ -9,8 +9,14 @@ use tauri_plugin_window_state::StateFlags;
|
|
|
9
9
|
#[cfg(target_os = "macos")]
|
|
10
10
|
use std::time::Duration;
|
|
11
11
|
|
|
12
|
+
use tauri::menu::{AboutMetadata, Menu, MenuItem, PredefinedMenuItem, Submenu};
|
|
13
|
+
use tauri_plugin_opener::OpenerExt; // Add this
|
|
14
|
+
|
|
12
15
|
use app::{
|
|
13
|
-
invoke::{
|
|
16
|
+
invoke::{
|
|
17
|
+
clear_cache_and_restart, download_file, download_file_by_binary, send_notification,
|
|
18
|
+
update_theme_mode,
|
|
19
|
+
},
|
|
14
20
|
setup::{set_global_shortcut, set_system_tray},
|
|
15
21
|
window::set_window,
|
|
16
22
|
};
|
|
@@ -42,7 +48,8 @@ pub fn run_app() {
|
|
|
42
48
|
.plugin(tauri_plugin_oauth::init())
|
|
43
49
|
.plugin(tauri_plugin_http::init())
|
|
44
50
|
.plugin(tauri_plugin_shell::init())
|
|
45
|
-
.plugin(tauri_plugin_notification::init())
|
|
51
|
+
.plugin(tauri_plugin_notification::init())
|
|
52
|
+
.plugin(tauri_plugin_opener::init()); // Add this
|
|
46
53
|
|
|
47
54
|
// Only add single instance plugin if multiple instances are not allowed
|
|
48
55
|
if !multi_instance {
|
|
@@ -60,8 +67,246 @@ pub fn run_app() {
|
|
|
60
67
|
download_file,
|
|
61
68
|
download_file_by_binary,
|
|
62
69
|
send_notification,
|
|
70
|
+
update_theme_mode,
|
|
71
|
+
clear_cache_and_restart,
|
|
63
72
|
])
|
|
64
73
|
.setup(move |app| {
|
|
74
|
+
// --- Menu Construction Start ---
|
|
75
|
+
let pake_version = env!("CARGO_PKG_VERSION");
|
|
76
|
+
let pake_menu_item_title = format!("Built with Pake V{}", pake_version);
|
|
77
|
+
|
|
78
|
+
// App Menu (macOS specific, e.g., "Pake")
|
|
79
|
+
let app_menu = Submenu::new(app, "Pake", true)?;
|
|
80
|
+
let about_metadata = AboutMetadata::default();
|
|
81
|
+
app_menu.append(&PredefinedMenuItem::about(
|
|
82
|
+
app,
|
|
83
|
+
Some("Pake"),
|
|
84
|
+
Some(about_metadata),
|
|
85
|
+
)?)?;
|
|
86
|
+
app_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
87
|
+
app_menu.append(&PredefinedMenuItem::services(app, None)?)?;
|
|
88
|
+
app_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
89
|
+
app_menu.append(&PredefinedMenuItem::hide(app, None)?)?;
|
|
90
|
+
app_menu.append(&PredefinedMenuItem::hide_others(app, None)?)?;
|
|
91
|
+
app_menu.append(&PredefinedMenuItem::show_all(app, None)?)?;
|
|
92
|
+
app_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
93
|
+
app_menu.append(&PredefinedMenuItem::quit(app, None)?)?;
|
|
94
|
+
|
|
95
|
+
// File Menu
|
|
96
|
+
let file_menu = Submenu::new(app, "File", true)?;
|
|
97
|
+
file_menu.append(&PredefinedMenuItem::close_window(app, None)?)?;
|
|
98
|
+
file_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
99
|
+
file_menu.append(&MenuItem::with_id(
|
|
100
|
+
app,
|
|
101
|
+
"clear_cache_restart",
|
|
102
|
+
"Clear Cache & Restart",
|
|
103
|
+
true,
|
|
104
|
+
Some("CmdOrCtrl+Shift+Backspace"),
|
|
105
|
+
)?)?;
|
|
106
|
+
|
|
107
|
+
// Edit Menu
|
|
108
|
+
let edit_menu = Submenu::new(app, "Edit", true)?;
|
|
109
|
+
edit_menu.append(&PredefinedMenuItem::undo(app, None)?)?;
|
|
110
|
+
edit_menu.append(&PredefinedMenuItem::redo(app, None)?)?;
|
|
111
|
+
edit_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
112
|
+
edit_menu.append(&PredefinedMenuItem::cut(app, None)?)?;
|
|
113
|
+
edit_menu.append(&PredefinedMenuItem::copy(app, None)?)?;
|
|
114
|
+
edit_menu.append(&PredefinedMenuItem::paste(app, None)?)?;
|
|
115
|
+
edit_menu.append(&PredefinedMenuItem::select_all(app, None)?)?;
|
|
116
|
+
edit_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
117
|
+
edit_menu.append(&MenuItem::with_id(
|
|
118
|
+
app,
|
|
119
|
+
"copy_url",
|
|
120
|
+
"Copy URL",
|
|
121
|
+
true,
|
|
122
|
+
Some("CmdOrCtrl+L"),
|
|
123
|
+
)?)?;
|
|
124
|
+
|
|
125
|
+
// View Menu
|
|
126
|
+
let view_menu = Submenu::new(app, "View", true)?;
|
|
127
|
+
view_menu.append(&MenuItem::with_id(
|
|
128
|
+
app,
|
|
129
|
+
"reload",
|
|
130
|
+
"Reload",
|
|
131
|
+
true,
|
|
132
|
+
Some("CmdOrCtrl+R"),
|
|
133
|
+
)?)?;
|
|
134
|
+
view_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
135
|
+
view_menu.append(&MenuItem::with_id(
|
|
136
|
+
app,
|
|
137
|
+
"zoom_in",
|
|
138
|
+
"Zoom In",
|
|
139
|
+
true,
|
|
140
|
+
Some("CmdOrCtrl+="),
|
|
141
|
+
)?)?;
|
|
142
|
+
view_menu.append(&MenuItem::with_id(
|
|
143
|
+
app,
|
|
144
|
+
"zoom_out",
|
|
145
|
+
"Zoom Out",
|
|
146
|
+
true,
|
|
147
|
+
Some("CmdOrCtrl+-"),
|
|
148
|
+
)?)?;
|
|
149
|
+
view_menu.append(&MenuItem::with_id(
|
|
150
|
+
app,
|
|
151
|
+
"zoom_reset",
|
|
152
|
+
"Actual Size",
|
|
153
|
+
true,
|
|
154
|
+
Some("CmdOrCtrl+0"),
|
|
155
|
+
)?)?;
|
|
156
|
+
view_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
157
|
+
view_menu.append(&PredefinedMenuItem::fullscreen(app, None)?)?;
|
|
158
|
+
view_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
159
|
+
view_menu.append(&MenuItem::with_id(
|
|
160
|
+
app,
|
|
161
|
+
"toggle_devtools",
|
|
162
|
+
"Toggle Developer Tools",
|
|
163
|
+
cfg!(debug_assertions),
|
|
164
|
+
Some("CmdOrCtrl+Option+I"),
|
|
165
|
+
)?)?;
|
|
166
|
+
|
|
167
|
+
// Navigation Menu
|
|
168
|
+
let navigation_menu = Submenu::new(app, "Navigation", true)?;
|
|
169
|
+
navigation_menu.append(&MenuItem::with_id(
|
|
170
|
+
app,
|
|
171
|
+
"go_back",
|
|
172
|
+
"Back",
|
|
173
|
+
true,
|
|
174
|
+
Some("CmdOrCtrl+["),
|
|
175
|
+
)?)?;
|
|
176
|
+
navigation_menu.append(&MenuItem::with_id(
|
|
177
|
+
app,
|
|
178
|
+
"go_forward",
|
|
179
|
+
"Forward",
|
|
180
|
+
true,
|
|
181
|
+
Some("CmdOrCtrl+]"),
|
|
182
|
+
)?)?;
|
|
183
|
+
navigation_menu.append(&MenuItem::with_id(
|
|
184
|
+
app,
|
|
185
|
+
"go_home",
|
|
186
|
+
"Go Home",
|
|
187
|
+
true,
|
|
188
|
+
Some("CmdOrCtrl+Shift+H"),
|
|
189
|
+
)?)?;
|
|
190
|
+
|
|
191
|
+
// Window Menu
|
|
192
|
+
let window_menu = Submenu::new(app, "Window", true)?;
|
|
193
|
+
window_menu.append(&PredefinedMenuItem::minimize(app, None)?)?;
|
|
194
|
+
window_menu.append(&PredefinedMenuItem::maximize(app, None)?)?;
|
|
195
|
+
window_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
196
|
+
window_menu.append(&MenuItem::with_id(
|
|
197
|
+
app,
|
|
198
|
+
"always_on_top",
|
|
199
|
+
"Toggle Always on Top",
|
|
200
|
+
true,
|
|
201
|
+
None::<&str>,
|
|
202
|
+
)?)?;
|
|
203
|
+
window_menu.append(&PredefinedMenuItem::separator(app)?)?;
|
|
204
|
+
window_menu.append(&PredefinedMenuItem::close_window(app, None)?)?;
|
|
205
|
+
|
|
206
|
+
// Help Menu (Custom)
|
|
207
|
+
let help_menu = Submenu::new(app, "Help", true)?;
|
|
208
|
+
let github_item = MenuItem::with_id(
|
|
209
|
+
app,
|
|
210
|
+
"pake_github_link",
|
|
211
|
+
&pake_menu_item_title,
|
|
212
|
+
true,
|
|
213
|
+
None::<&str>,
|
|
214
|
+
)?;
|
|
215
|
+
help_menu.append(&github_item)?;
|
|
216
|
+
|
|
217
|
+
// Construct the Menu Bar
|
|
218
|
+
let menu = Menu::with_items(
|
|
219
|
+
app,
|
|
220
|
+
&[
|
|
221
|
+
&app_menu,
|
|
222
|
+
&file_menu,
|
|
223
|
+
&edit_menu,
|
|
224
|
+
&view_menu,
|
|
225
|
+
&navigation_menu,
|
|
226
|
+
&window_menu,
|
|
227
|
+
&help_menu,
|
|
228
|
+
],
|
|
229
|
+
)?;
|
|
230
|
+
|
|
231
|
+
app.set_menu(menu)?;
|
|
232
|
+
|
|
233
|
+
// Event Handling for Custom Menu Item
|
|
234
|
+
app.on_menu_event(move |app_handle, event| {
|
|
235
|
+
match event.id().as_ref() {
|
|
236
|
+
"pake_github_link" => {
|
|
237
|
+
let _ = app_handle
|
|
238
|
+
.opener()
|
|
239
|
+
.open_url("https://github.com/tw93/Pake", None::<&str>);
|
|
240
|
+
}
|
|
241
|
+
"reload" => {
|
|
242
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
243
|
+
let _ = window.eval("window.location.reload()");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
"toggle_devtools" => {
|
|
247
|
+
#[cfg(debug_assertions)] // Only allow in debug builds
|
|
248
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
249
|
+
if window.is_devtools_open() {
|
|
250
|
+
window.close_devtools();
|
|
251
|
+
} else {
|
|
252
|
+
window.open_devtools();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
"zoom_in" => {
|
|
257
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
258
|
+
let _ = window.eval("zoomIn()");
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
"zoom_out" => {
|
|
262
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
263
|
+
let _ = window.eval("zoomOut()");
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
"zoom_reset" => {
|
|
267
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
268
|
+
let _ = window.eval("setZoom('100%')");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
"go_back" => {
|
|
272
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
273
|
+
let _ = window.eval("window.history.back()");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
"go_forward" => {
|
|
277
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
278
|
+
let _ = window.eval("window.history.forward()");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
"go_home" => {
|
|
282
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
283
|
+
let _ = window.eval("window.location.href = window.pakeConfig.url");
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
"copy_url" => {
|
|
287
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
288
|
+
let _ =
|
|
289
|
+
window.eval("navigator.clipboard.writeText(window.location.href)");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
"clear_cache_restart" => {
|
|
293
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
294
|
+
if let Ok(_) = window.clear_all_browsing_data() {
|
|
295
|
+
app_handle.restart();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
"always_on_top" => {
|
|
300
|
+
if let Some(window) = app_handle.get_webview_window("pake") {
|
|
301
|
+
let is_on_top = window.is_always_on_top().unwrap_or(false);
|
|
302
|
+
let _ = window.set_always_on_top(!is_on_top);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
_ => {}
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
// --- Menu Construction End ---
|
|
309
|
+
|
|
65
310
|
let window = set_window(app, &pake_config, &tauri_config);
|
|
66
311
|
set_system_tray(
|
|
67
312
|
app.app_handle(),
|