diff --git a/src-tauri/pake.json b/src-tauri/pake.json index a97dcc7..eb64fc0 100644 --- a/src-tauri/pake.json +++ b/src-tauri/pake.json @@ -1,7 +1,7 @@ { "windows": [ { - "url": "https://weread.qq.com/", + "url": "https://twitter.com/home", "transparent": true, "fullscreen": false, "width": 1200, diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs index 245abbc..236c4f7 100644 --- a/src-tauri/src/app/window.rs +++ b/src-tauri/src/app/window.rs @@ -1,43 +1,46 @@ use crate::app::config::PakeConfig; +use std::path::PathBuf; use tauri::{App, TitleBarStyle, Window, WindowBuilder, WindowUrl}; -pub fn get_window(app: &mut App, config: PakeConfig, _data_dir: std::path::PathBuf) -> Window { - let window_config = config.windows.first().unwrap(); - let user_agent = config.user_agent; +pub fn get_window(app: &mut App, config: PakeConfig, _data_dir: PathBuf) -> Window { + let window_config = config + .windows + .first() + .expect("At least one window configuration is required"); + + #[cfg(target_os = "macos")] + let user_agent = config.user_agent.macos.as_str(); + #[cfg(target_os = "linux")] + let user_agent = config.user_agent.linux.as_str(); + #[cfg(target_os = "windows")] + let user_agent = config.user_agent.windows.as_str(); + let url = match window_config.url_type.as_str() { "web" => WindowUrl::App(window_config.url.parse().unwrap()), - "local" => WindowUrl::App(std::path::PathBuf::from(&window_config.url)), + "local" => WindowUrl::App(PathBuf::from(&window_config.url)), _ => panic!("url type only can be web or local"), }; - #[cfg(target_os = "macos")] - let window = WindowBuilder::new(app, "pake", url) + + let title_bar_style = if window_config.transparent { + TitleBarStyle::Overlay + } else { + TitleBarStyle::Visible + }; + + let window_builder = WindowBuilder::new(app, "pake", url) .title("") - .user_agent(user_agent.macos.as_str()) + .user_agent(user_agent) .resizable(window_config.resizable) .fullscreen(window_config.fullscreen) - //用于隐藏头部 - .title_bar_style(if window_config.transparent { - TitleBarStyle::Overlay - } else { - TitleBarStyle::Visible - }) + .title_bar_style(title_bar_style) .inner_size(window_config.width, window_config.height) - .initialization_script(include_str!("../inject.js")); + .initialization_script(include_str!("../inject/style.js")) + .initialization_script(include_str!("../inject/index.js")); #[cfg(not(target_os = "macos"))] - let window = { - #[cfg(target_os = "linux")] - let user_agent = user_agent.linux.as_str(); - #[cfg(target_os = "windows")] - let user_agent = user_agent.windows.as_str(); - WindowBuilder::new(app, "pake", url) - .title("") - .data_directory(_data_dir) - .resizable(window_config.resizable) - .fullscreen(window_config.fullscreen) - .user_agent(user_agent) - .inner_size(window_config.width, window_config.height) - .initialization_script(include_str!("../inject.js")) - }; - window.build().unwrap() + { + window_builder = window_builder.data_directory(_data_dir); + } + + window_builder.build().unwrap() } diff --git a/src-tauri/src/inject/index.js b/src-tauri/src/inject/index.js new file mode 100644 index 0000000..60e4df8 --- /dev/null +++ b/src-tauri/src/inject/index.js @@ -0,0 +1,133 @@ +const shortcuts = { + ArrowUp: () => scrollTo(0, 0), + ArrowDown: () => scrollTo(0, document.body.scrollHeight), + ArrowLeft: () => window.history.back(), + ArrowRight: () => window.history.forward(), + '[': () => window.history.back(), + ']': () => window.history.forward(), + r: () => window.location.reload(), + '-': () => zoomOut(), + '=': () => zoomIn(), + '+': () => zoomIn(), + 0: () => setZoom('100%'), +}; + +function setZoom(zoom) { + const html = document.getElementsByTagName('html')[0]; + html.style.zoom = zoom; + window.localStorage.setItem('htmlZoom', zoom); +} + +function zoomCommon(zoomChange) { + const currentZoom = window.localStorage.getItem('htmlZoom') || '100%'; + setZoom(zoomChange(currentZoom)); +} + +function zoomIn() { + zoomCommon((currentZoom) => `${Math.min(parseInt(currentZoom) + 10, 200)}%`); +} + +function zoomOut() { + zoomCommon((currentZoom) => `${Math.max(parseInt(currentZoom) - 10, 30)}%`); +} + +function handleShortcut(event) { + if (shortcuts[event.key]) { + event.preventDefault(); + shortcuts[event.key](); + } +} + +//这里参考 ChatGPT 的代码 +const uid = () => window.crypto.getRandomValues(new Uint32Array(1))[0]; +function transformCallback(callback = () => {}, once = false) { + const identifier = uid(); + const prop = `_${identifier}`; + Object.defineProperty(window, prop, { + value: (result) => { + if (once) { + Reflect.deleteProperty(window, prop); + } + return callback(result); + }, + writable: false, + configurable: true, + }); + return identifier; +} +async function invoke(cmd, args) { + return new Promise((resolve, reject) => { + if (!window.__TAURI_POST_MESSAGE__) + reject('__TAURI_POST_MESSAGE__ does not exist~'); + const callback = transformCallback((e) => { + resolve(e); + Reflect.deleteProperty(window, `_${error}`); + }, true); + const error = transformCallback((e) => { + reject(e); + Reflect.deleteProperty(window, `_${callback}`); + }, true); + window.__TAURI_POST_MESSAGE__({ + cmd, + callback, + error, + ...args, + }); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + const topDom = document.createElement('div'); + topDom.id = 'pack-top-dom'; + document.body.appendChild(topDom); + const domEl = document.getElementById('pack-top-dom'); + + domEl.addEventListener('mousedown', (e) => { + if (e.buttons === 1 && e.detail !== 2) { + invoke('drag_window'); + } + }); + + domEl.addEventListener('touchstart', () => { + invoke('drag_window'); + }); + + domEl.addEventListener('dblclick', () => { + invoke('fullscreen'); + }); + + document.addEventListener('keyup', (event) => { + if (/windows|linux/i.test(navigator.userAgent) && event.ctrlKey) { + handleShortcut(event); + } + if (/macintosh|mac os x/i.test(navigator.userAgent) && event.metaKey) { + handleShortcut(event); + } + }); + + document.addEventListener('click', (e) => { + const origin = e.target.closest('a'); + if (origin && origin.href) { + const target = origin.target; + origin.target = '_self'; + const hrefUrl = new URL(origin.href); + + if ( + window.location.host !== hrefUrl.host && // 如果 a 标签内链接的域名和当前页面的域名不一致 且 + target === '_blank' // a 标签内链接的 target 属性为 _blank 时 + ) { + e.preventDefault(); + invoke('open_browser', { url: origin.href }); + } + } + }); + + setDefaultZoom(); +}); + +function setDefaultZoom() { + const htmlZoom = window.localStorage.getItem('htmlZoom'); + if (htmlZoom) { + setZoom(htmlZoom); + } +} diff --git a/src-tauri/src/inject.js b/src-tauri/src/inject/style.js similarity index 61% rename from src-tauri/src/inject.js rename to src-tauri/src/inject/style.js index bca65a2..5a4af47 100644 --- a/src-tauri/src/inject.js +++ b/src-tauri/src/inject/style.js @@ -1,67 +1,5 @@ -const metaKeyShortcuts = { - ArrowUp: () => scrollTo(0, 0), - ArrowDown: () => scrollTo(0, document.body.scrollHeight), - '[': () => window.history.back(), - ']': () => window.history.forward(), - r: () => window.location.reload(), - '-': () => zoomOut(), - '=': () => zoomIn(), - '+': () => zoomIn(), - 0: () => zoomCommon(() => '100%'), -}; - -const ctrlKeyShortcuts = { - ArrowUp: () => scrollTo(0, 0), - ArrowDown: () => scrollTo(0, document.body.scrollHeight), - ArrowLeft: () => window.history.back(), - ArrowRight: () => window.history.forward(), - r: () => window.location.reload(), - '-': () => zoomOut(), - '=': () => zoomIn(), - '+': () => zoomIn(), - 0: () => zoomCommon(() => '100%'), -}; - -const uid = () => window.crypto.getRandomValues(new Uint32Array(1))[0]; -function transformCallback(callback = () => {}, once = false) { - const identifier = uid(); - const prop = `_${identifier}`; - Object.defineProperty(window, prop, { - value: (result) => { - if (once) { - Reflect.deleteProperty(window, prop); - } - return callback(result); - }, - writable: false, - configurable: true, - }); - return identifier; -} -async function invoke(cmd, args) { - return new Promise((resolve, reject) => { - if (!window.__TAURI_POST_MESSAGE__) - reject('__TAURI_POST_MESSAGE__ does not exist~'); - const callback = transformCallback((e) => { - resolve(e); - Reflect.deleteProperty(window, `_${error}`); - }, true); - const error = transformCallback((e) => { - reject(e); - Reflect.deleteProperty(window, `_${callback}`); - }, true); - window.__TAURI_POST_MESSAGE__({ - cmd, - callback, - error, - ...args, - }); - }); -} - window.addEventListener('DOMContentLoaded', (_event) => { - const style = document.createElement('style'); - style.innerHTML = ` + const css = ` #page #footer-wrapper, .drawing-board .toolbar .toolbar-action, .c-swiper-container, @@ -300,89 +238,11 @@ window.addEventListener('DOMContentLoaded', (_event) => { height: 20px; cursor: grab; cursor: -webkit-grab; + -webkit-app-region: drag; z-index: 90000; } `; - document.head.append(style); - const topDom = document.createElement('div'); - topDom.id = 'pack-top-dom'; - document.body.appendChild(topDom); - - const domEl = document.getElementById('pack-top-dom'); - - domEl.addEventListener('mousedown', (e) => { - if (e.buttons === 1 && e.detail !== 2) { - invoke('drag_window'); - } - }); - - domEl.addEventListener('touchstart', () => { - invoke('drag_window'); - }); - - domEl.addEventListener('dblclick', () => { - invoke('fullscreen'); - }); - - document.addEventListener('keyup', function (event) { - const preventDefault = (f) => { - event.preventDefault(); - f(); - }; - if (/windows|linux/i.test(navigator.userAgent)) { - if (event.ctrlKey && event.key in ctrlKeyShortcuts) { - preventDefault(ctrlKeyShortcuts[event.key]); - } - } - if (/macintosh|mac os x/i.test(navigator.userAgent)) { - if (event.metaKey && event.key in metaKeyShortcuts) { - preventDefault(metaKeyShortcuts[event.key]); - } - } - }); - - document.addEventListener('click', (e) => { - const origin = e.target.closest('a'); - if (origin && origin.href) { - const target = origin.target; - origin.target = '_self'; - const hrefUrl = new URL(origin.href); - - if ( - window.location.host !== hrefUrl.host && // 如果 a 标签内链接的域名和当前页面的域名不一致 且 - target === '_blank' // a 标签内链接的 target 属性为 _blank 时 - ) { - e.preventDefault(); - invoke('open_browser', { url: origin.href }); - } - } - }); + const styleElement = document.createElement('style'); + styleElement.innerHTML = css; + document.head.appendChild(styleElement); }); - -setDefaultZoom(); - -function setDefaultZoom() { - const htmlZoom = window.localStorage.getItem('htmlZoom'); - if (htmlZoom) { - document.getElementsByTagName('html')[0].style.zoom = htmlZoom; - } -} - -/** - * @param {(htmlZoom: string) => string} [zoomRule] - */ -function zoomCommon(zoomRule) { - const htmlZoom = window.localStorage.getItem('htmlZoom') || '100%'; - const html = document.getElementsByTagName('html')[0]; - const zoom = zoomRule(htmlZoom); - html.style.zoom = zoom; - window.localStorage.setItem('htmlZoom', zoom); -} - -function zoomIn() { - zoomCommon((htmlZoom) => `${Math.min(parseInt(htmlZoom) + 10, 200)}%`); -} - -function zoomOut() { - zoomCommon((htmlZoom) => `${Math.max(parseInt(htmlZoom) - 10, 30)}%`); -} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index c94da50..b3946ab 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -18,39 +18,25 @@ pub fn run_app() { let menu = get_menu(); let data_dir = get_data_dir(tauri_config); - #[cfg(target_os = "macos")] - let tauri_app = if show_menu { - tauri::Builder::default() - .menu(menu) - .on_menu_event(menu_event_handle) - } else { - tauri::Builder::default() - }; + let mut tauri_app = tauri::Builder::default(); + + if show_menu { + tauri_app = tauri_app.menu(menu).on_menu_event(menu_event_handle); + } #[cfg(not(target_os = "macos"))] - let tauri_app = { + { use pake::{get_system_tray, system_tray_handle}; let show_system_tray = pake_config.show_system_tray(); let system_tray = get_system_tray(show_menu); - let tauri_app = if show_menu && !show_system_tray { - tauri::Builder::default() - .menu(menu) - .on_menu_event(menu_event_handle) - } else if !show_menu && show_system_tray { - tauri::Builder::default() + + if show_system_tray { + tauri_app = tauri_app .system_tray(system_tray) - .on_system_tray_event(system_tray_handle) - } else if show_menu && show_system_tray { - tauri::Builder::default() - .menu(menu) - .on_menu_event(menu_event_handle) - .system_tray(system_tray) - .on_system_tray_event(system_tray_handle) - } else { - tauri::Builder::default() - }; - }; + .on_system_tray_event(system_tray_handle); + } + } tauri_app .plugin(tauri_plugin_window_state::Builder::default().build()) diff --git a/src-tauri/src/util.rs b/src-tauri/src/util.rs index bc9aec6..c9fa7c3 100644 --- a/src-tauri/src/util.rs +++ b/src-tauri/src/util.rs @@ -1,36 +1,37 @@ use crate::app::config::PakeConfig; use tauri::Config; +use std::path::PathBuf; pub fn get_pake_config() -> (PakeConfig, Config) { - let pake_config_path = include_str!("../pake.json"); let pake_config: PakeConfig = - serde_json::from_str(pake_config_path).expect("failed to parse pake config"); - // println!("{:#?}", config); - let tauri_config_path = include_str!("../tauri.conf.json"); - let tauri_config: Config = - serde_json::from_str(tauri_config_path).expect("failed to parse tauri config"); + serde_json::from_str(include_str!("../pake.json")).expect("failed to parse pake config"); + + let tauri_config: Config = serde_json::from_str(include_str!("../tauri.conf.json")) + .expect("failed to parse tauri config"); + (pake_config, tauri_config) } -pub fn get_data_dir(_tauri_config: Config) -> std::path::PathBuf { +pub fn get_data_dir(_tauri_config: Config) -> PathBuf { #[cfg(any(target_os = "linux", target_os = "windows"))] - let data_dir = { + { let package_name = _tauri_config.package.product_name.unwrap(); - let home_dir = match home::home_dir() { - Some(path1) => path1, - None => panic!("Error, can't found you home dir!!"), + let home_dir = home::home_dir().expect("Error, can't found your home dir!!"); + + let data_dir = match cfg!(target_os = "windows") { + true => home_dir.join("AppData").join("Roaming").join(package_name), + false => home_dir.join(".config").join(package_name), }; - #[cfg(target_os = "windows")] - let data_dir = home_dir.join("AppData").join("Roaming").join(package_name); - #[cfg(target_os = "linux")] - let data_dir = home_dir.join(".config").join(package_name); + if !data_dir.exists() { std::fs::create_dir(&data_dir) .unwrap_or_else(|_| panic!("can't create dir {}", data_dir.display())); } data_dir - }; + } #[cfg(target_os = "macos")] - let data_dir = std::path::PathBuf::new(); - data_dir + { + PathBuf::new() + } } +