diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41c0f5b..79f1a96 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,6 @@ name: Release CI on: push: - # Sequence of patterns matched against refs/tags tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 @@ -90,7 +89,7 @@ jobs: # 📝: Edit the deployment directory publish_dir: ./updater force_orphan: true - + publish-winget: # Action can only be run on windows runs-on: windows-latest @@ -99,5 +98,5 @@ jobs: - uses: vedantmgoyal2009/winget-releaser@v1 with: identifier: lencx.ChatGPT - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.WINGET_TOKEN }} version: ${{ env.version }} diff --git a/README-ZH_CN.md b/README-ZH_CN.md index 7582711..3cee45d 100644 --- a/README-ZH_CN.md +++ b/README-ZH_CN.md @@ -1,10 +1,9 @@

ChatGPT

ChatGPT

+

ChatGPT 桌面应用(Mac, Windows and Linux)

-> ChatGPT 桌面应用 - [![English badge](https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)](./README.md) [![简体中文 badge](https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-Simplified%20Chinese-blue)](./README-ZH_CN.md)\ ![License](https://img.shields.io/badge/License-Apache%202-green.svg) @@ -23,24 +22,29 @@ ### Windows -- [ChatGPT_0.7.4_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64_en-US.msi) -- 或者使用 [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/): - - `winget install --id=lencx.ChatGPT -e` - - `winget install --id=lencx.ChatGPT -e --version 0.7.4` +- [ChatGPT_0.8.0_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64_en-US.msi): +- 使用 [winget](https://winstall.app/apps/lencx.ChatGPT): + ```bash + # install the latest version + winget install --id=lencx.ChatGPT -e -**注意:如果安装路径和应用名称相同,会导致冲突 ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-1371166972))** + # install the specified version + winget install --id=lencx.ChatGPT -e --version 0.7.4 + ``` + +**注意:如果安装路径和应用名称相同,会导致冲突 ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-0.8.0))** ### Mac -- [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg) -- 如果你偏爱 `.app` 的安装包,你同样可以在我们的 github releases 里找到 [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT.app.tar.gz) +- [ChatGPT_0.8.0_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64.dmg) +- [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT.app.tar.gz) - Homebrew \ _[Homebrew 快捷安装](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_ ```sh brew tap lencx/chatgpt https://github.com/lencx/ChatGPT.git brew install --cask chatgpt --no-quarantine ``` - 如果你坚持使用 _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_ ,你需要添加以下配置: + 如果你坚持使用 _[Brewfile](https://github.com/Homebrew/homebrew-bundle#usage)_ ,则需要添加以下配置: ```rb repo = "lencx/chatgpt" tap repo, "https://github.com/#{repo}.git" @@ -49,24 +53,25 @@ ### Linux -- [chat-gpt_0.7.4_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.deb) -- [chat-gpt_0.7.4_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.AppImage): **工作可靠,`.deb` 运行失败时可以尝试它** -- [chatgpt-desktop-bin](https://aur.archlinux.org/packages/chatgpt-desktop-bin): 使用 AUR 来安装 +- [chat-gpt_0.8.0_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.deb) +- [chat-gpt_0.8.0_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.AppImage): **工作可靠,`.deb` 运行失败时可以尝试它** +- 使用 [AUR](https://aur.archlinux.org/packages/chatgpt-desktop-bin): + ```bash + yay -S chatgpt-desktop-bin + ``` ---- - ## 📢 公告 这是一个令人兴奋的重大更新。像 `Telegram 机器人指令` 那样工作,帮助你快速填充自定模型,来让 ChatGPT 按照你想要的方式去工作。这个项目倾注了我大量业余时间,如果它对你有所帮助,宣传转发,或者 star 都是对我的巨大鼓励。我希望我可以持续更新下去,加入更多有趣的功能。 ### 如何使用指令? -你可以从 [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) 来寻找有趣的功能来导入到应用。 +你可以从 [awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts) 来寻找有趣的功能来导入到应用。也可以使用 `Sync Prompts`,来一键同步所有,如果你不想让某些提示出现在你的斜杠命令,你可以禁用它们。 -![chat cmd](./assets/chat-cmd-1.png) -![chat cmd](./assets/chat-cmd-2.png) +![chatgpt menu](./assets/chatgpt-menu.png) +![chatgpt sync prompts](./assets/chatgpt-sync-prompts.png) @@ -85,11 +90,12 @@ - 应用菜单功能强大 - 支持斜杠命令及其配置(可手动配置或从文件同步 [#55](https://github.com/lencx/ChatGPT/issues/55)) - 自定义全局快捷键 ([#108](https://github.com/lencx/ChatGPT/issues/108)) +- 划词搜索 ([#122](https://github.com/lencx/ChatGPT/issues/122) 鼠标选中文本,不超过 400 个字符):应用使用 Tauri 构建,因其安全限制,会导致部分操作按钮无效,建议前往浏览器操作。 -### 菜单项 +### #️⃣ 菜单项 - **Preferences (喜好)** - - `Theme` - `Light`, `Dark` (仅支持 macOS 和 Windows) + - `Theme` - `Light`, `Dark`, `System` (仅支持 macOS 和 Windows) - `Stay On Top`: 窗口置顶 - `Titlebar`: 是否显示 `Titlebar`,仅 macOS 支持 - `Inject Script`: 用于修改网站的用户自定义脚本 @@ -110,7 +116,7 @@ - `Report Bug`: 报告 BUG 或反馈建议 - `Toggle Developer Tools`: 网站调试工具,调试页面或脚本可能需要 -## 应用配置 +## ⚙️ 应用配置 | 平台 | 路径 | | ------- | ------------------------- | @@ -163,9 +169,9 @@ ## 👀 预览 -install control center -export tray -tray login auto update +install control center +export dalle2 tray +auto update ## ❓ 常见问题 @@ -187,6 +193,8 @@ Mac 上无法安装,提示开发者未验证,具体可以查看下面给出 - [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac) +--- + ### 我想自己构建它? #### 预安装 diff --git a/README.md b/README.md index 9afc75f..53a03f4 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@

ChatGPT

ChatGPT

+

ChatGPT Desktop Application (Mac, Windows and Linux)

-

ChatGPT Desktop Application

-
- [![English badge](https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)](./README.md) [![简体中文 badge](https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-Simplified%20Chinese-blue)](./README-ZH_CN.md)\ ![License](https://img.shields.io/badge/License-Apache%202-green.svg) @@ -26,17 +24,22 @@ ### Windows -- From our github releases: [ChatGPT_0.7.4_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64_en-US.msi) -- Or install with [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/): - - `winget install --id=lencx.ChatGPT -e` - - `winget install --id=lencx.ChatGPT -e --version 0.7.4` +- [ChatGPT_0.8.0_x64_en-US.msi](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64_en-US.msi): Direct download installer +- Use [winget](https://winstall.app/apps/lencx.ChatGPT): + ```bash + # install the latest version + winget install --id=lencx.ChatGPT -e -**Note: If the installation path and application name are the same, it will lead to conflict ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-1371166972))** + # install the specified version + winget install --id=lencx.ChatGPT -e --version 0.7.4 + ``` + +**Note: If the installation path and application name are the same, it will lead to conflict ([#142](https://github.com/lencx/ChatGPT/issues/142#issuecomment-0.8.0))** ### Mac -- From our github releases: [ChatGPT_0.7.4_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT_0.7.4_x64.dmg) -- If you prefer `.app` installation, you can also download it from our github releases: [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/ChatGPT.app.tar.gz) +- [ChatGPT_0.8.0_x64.dmg](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT_0.8.0_x64.dmg): Direct download installer +- [ChatGPT.app.tar.gz](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/ChatGPT.app.tar.gz): Download the `.app` installer - Homebrew \ Or you can install with _[Homebrew](https://brew.sh) ([Cask](https://docs.brew.sh/Cask-Cookbook)):_ ```sh @@ -52,14 +55,12 @@ ### Linux -- [chat-gpt_0.7.4_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.deb) -- [chat-gpt_0.7.4_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.7.4/chat-gpt_0.7.4_amd64.AppImage): **works reliably, you can try it if `.deb` fails to run** +- [chat-gpt_0.8.0_amd64.deb](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.deb): Download `.deb` installer, advantage small size, disadvantage poor compatibility +- [chat-gpt_0.8.0_amd64.AppImage](https://github.com/lencx/ChatGPT/releases/download/v0.8.0/chat-gpt_0.8.0_amd64.AppImage): Works reliably, you can try it if `.deb` fails to run - Available on [AUR](https://aur.archlinux.org/packages/chatgpt-desktop-bin) with the package name `chatgpt-desktop-bin`, and you can use your favourite AUR package manager to install it. ---- - ## 📢 Announcement ### ChatGPT Prompts! @@ -68,22 +69,18 @@ This is a major and exciting update. It works like a `Telegram bot command` and ### How does it work? -You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts)** to find interesting features to import into the app. +You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt-prompts)** to find interesting features to import into the app. You can also use `Sync Prompts` to sync all in one click, and if you don't want certain prompts to appear in your slash commands, you can disable them. -![chat cmd](./assets/chat-cmd-1.png) - -![chat cmd](./assets/chat-cmd-2.png) +![chatgpt menu](./assets/chatgpt-menu.png) +![chatgpt sync prompts](./assets/chatgpt-sync-prompts.png) -
- In the chatgpt text input area, type a character starting with `/` to bring up the command prompt, press the spacebar, and it will fill the input area with the text associated with the command by default (note: if it contains multiple command prompts, it will only select the first one as the fill, you can keep typing until the first prompted command is the one you want, then press the spacebar. - Or use the mouse to click on one of the multiple commands). When the fill is complete, you simply press the Enter key. - Under the slash command, use the tab key to modify the contents of the `{q}` tag (only single changes are supported [#54](https://github.com/lencx/ChatGPT/issues/54)). Use the keyboard `⇧` (arrow up) and `⇩` (arrow down) keys to select the slash command. -
![chatgpt](assets/chatgpt.gif) - ![chatgpt-cmd](assets/chatgpt-cmd.gif) ## ✨ Features @@ -96,11 +93,12 @@ You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt - Powerful menu items - Support for slash commands and their configuration (can be configured manually or synchronized from a file [#55](https://github.com/lencx/ChatGPT/issues/55)) - Customize global shortcuts ([#108](https://github.com/lencx/ChatGPT/issues/108)) +- Pop-up Search ([#122](https://github.com/lencx/ChatGPT/issues/122) mouse selected content, no more than 400 characters): The application is built using Tauri, and due to its security restrictions, some of the action buttons will not work, so we recommend going to your browser. -## MenuItem +## #️⃣ MenuItem - **Preferences** - - `Theme` - `Light`, `Dark` (Only macOS and Windows are supported). + - `Theme` - `Light`, `Dark`, `System` (Only macOS and Windows are supported). - `Stay On Top`: The window is stay on top of other windows. - `Titlebar`: Whether to display the titlebar, supported by macOS only. - `Hide Dock Icon` ([#35](https://github.com/lencx/ChatGPT/issues/35)): Hide application icons from the Dock(support macOS only). @@ -121,7 +119,7 @@ You can look at **[awesome-chatgpt-prompts](https://github.com/f/awesome-chatgpt - `Report Bug`: Report a bug or give feedback. - `Toggle Developer Tools`: Developer debugging tools. -## Application Configuration +## ⚙️ Application Configuration | Platform | Path | | -------- | ------------------------- | @@ -172,18 +170,18 @@ Currently, only json and csv are supported for synchronizing custom files, and t "b","bb","bbb bbb bbb" ``` -## TODO +## 📌 TODO -- `Control Center` - Feature Enhancements -- Integration with [DALL·E 2](https://openai.com/dall-e-2/) ([#122](https://github.com/lencx/ChatGPT/issues/122)) +- `Control Center` enhancement +- `Pop-up Search` enhancement - ... ## 👀 Preview -install control center -export tray -tray login auto update +install popup search +control center export +dalle2 tray auto update ## ❓FAQ @@ -203,6 +201,8 @@ It's safe, just a wrapper for [OpenAI ChatGPT](https://chat.openai.com) website, - [Open a Mac app from an unidentified developer](https://support.apple.com/en-sg/guide/mac-help/mh40616/mac) +--- + ### How do i build it? #### PreInstall @@ -231,7 +231,6 @@ yarn dev # bundle path: src-tauri/target/release/bundle yarn build ``` ---- ## ❤️ Thanks diff --git a/UPDATE_LOG.md b/UPDATE_LOG.md index 8a6b166..062cce6 100644 --- a/UPDATE_LOG.md +++ b/UPDATE_LOG.md @@ -1,5 +1,15 @@ # UPDATE LOG +## v0.8.0 + +feat: +- theme enhancement (Light, Dark, System) +- automatic updates support `silent` settings +- pop-up search: select the ChatGPT content with the mouse, the `DALL·E 2` button appears, and click to jump (note: because the search content filled by the script cannot trigger the event directly, you need to enter a space in the input box to make the button clickable). + +fix: +- close the main window and hide it in the tray (windows systems) + ## v0.7.4 fix: diff --git a/assets/chat-cmd-1.png b/assets/chat-cmd-1.png deleted file mode 100644 index e83d4c2..0000000 Binary files a/assets/chat-cmd-1.png and /dev/null differ diff --git a/assets/chat-cmd-2.png b/assets/chat-cmd-2.png deleted file mode 100644 index 36e971c..0000000 Binary files a/assets/chat-cmd-2.png and /dev/null differ diff --git a/assets/chatgpt-control-center-general.png b/assets/chatgpt-control-center-general.png new file mode 100644 index 0000000..8cdc94e Binary files /dev/null and b/assets/chatgpt-control-center-general.png differ diff --git a/assets/chatgpt-dalle2-tray.png b/assets/chatgpt-dalle2-tray.png new file mode 100644 index 0000000..66cf204 Binary files /dev/null and b/assets/chatgpt-dalle2-tray.png differ diff --git a/assets/chatgpt-export.png b/assets/chatgpt-export.png new file mode 100644 index 0000000..1be711c Binary files /dev/null and b/assets/chatgpt-export.png differ diff --git a/assets/chatgpt-menu.png b/assets/chatgpt-menu.png new file mode 100644 index 0000000..5697725 Binary files /dev/null and b/assets/chatgpt-menu.png differ diff --git a/assets/chatgpt-popup-search.png b/assets/chatgpt-popup-search.png new file mode 100644 index 0000000..650f344 Binary files /dev/null and b/assets/chatgpt-popup-search.png differ diff --git a/assets/chatgpt-sync-prompts.png b/assets/chatgpt-sync-prompts.png new file mode 100644 index 0000000..2006952 Binary files /dev/null and b/assets/chatgpt-sync-prompts.png differ diff --git a/assets/control-center.png b/assets/control-center.png deleted file mode 100644 index 90b8d0d..0000000 Binary files a/assets/control-center.png and /dev/null differ diff --git a/assets/export.png b/assets/export.png deleted file mode 100644 index 6d580bc..0000000 Binary files a/assets/export.png and /dev/null differ diff --git a/assets/tray-login.png b/assets/tray-login.png deleted file mode 100644 index 0dad35b..0000000 Binary files a/assets/tray-login.png and /dev/null differ diff --git a/assets/tray.png b/assets/tray.png deleted file mode 100644 index de46b51..0000000 Binary files a/assets/tray.png and /dev/null differ diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3093a68..a25678f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -29,9 +29,12 @@ reqwest = "0.11.13" wry = "0.23.4" dark-light = "1.0.0" [dependencies.tauri-plugin-log] -git = "https://github.com/tauri-apps/tauri-plugin-log" +git = "https://github.com/lencx/tauri-plugin-log" branch = "dev" features = ["colored"] +[dependencies.tauri-plugin-autostart] +git = "https://github.com/lencx/tauri-plugin-autostart" +branch = "dev" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/app/cmd.rs b/src-tauri/src/app/cmd.rs index ae0e903..3d656fe 100644 --- a/src-tauri/src/app/cmd.rs +++ b/src-tauri/src/app/cmd.rs @@ -1,16 +1,28 @@ use crate::{ + app::window, conf::{ChatConfJson, GITHUB_PROMPTS_CSV_URL}, - utils::{self, exists}, + utils, }; use log::info; use std::{collections::HashMap, fs, path::PathBuf}; use tauri::{api, command, AppHandle, Manager, Theme}; +use walkdir::WalkDir; #[command] pub fn drag_window(app: AppHandle) { app.get_window("core").unwrap().start_dragging().unwrap(); } +#[command] +pub fn dalle2_window(app: AppHandle, query: String) { + window::dalle2_window( + &app.app_handle(), + Some(query), + Some("ChatGPT & DALL·E 2".to_string()), + None, + ); +} + #[command] pub fn fullscreen(app: AppHandle) { let win = app.get_window("core").unwrap(); @@ -49,8 +61,8 @@ pub fn reset_chat_conf() -> ChatConfJson { } #[command] -pub fn run_check_update(app: AppHandle, silent: bool) { - utils::run_check_update(app, silent).unwrap(); +pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option) { + utils::run_check_update(app, silent, has_msg); } #[command] @@ -127,9 +139,6 @@ pub fn window_reload(app: AppHandle, label: &str) { .unwrap(); } -use utils::chat_root; -use walkdir::WalkDir; - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct ModelRecord { pub cmd: String, @@ -142,7 +151,7 @@ pub struct ModelRecord { #[command] pub fn cmd_list() -> Vec { let mut list = vec![]; - for entry in WalkDir::new(chat_root().join("cache_model")) + for entry in WalkDir::new(utils::chat_root().join("cache_model")) .into_iter() .filter_map(|e| e.ok()) { @@ -182,11 +191,13 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option> let data2 = data.clone(); - let model = chat_root().join("chat.model.json"); - let model_cmd = chat_root().join("chat.model.cmd.json"); - let chatgpt_prompts = chat_root().join("cache_model").join("chatgpt_prompts.json"); + let model = utils::chat_root().join("chat.model.json"); + let model_cmd = utils::chat_root().join("chat.model.cmd.json"); + let chatgpt_prompts = utils::chat_root() + .join("cache_model") + .join("chatgpt_prompts.json"); - if !exists(&model) { + if !utils::exists(&model) { fs::write( &model, serde_json::json!({ @@ -236,7 +247,8 @@ pub async fn sync_prompts(app: AppHandle, time: u64) -> Option> "Sync Prompts", "ChatGPT Prompts data has been synchronized!", ); - window_reload(app, "core"); + window_reload(app.clone(), "core"); + window_reload(app, "tray"); return Some(data2); } diff --git a/src-tauri/src/app/menu.rs b/src-tauri/src/app/menu.rs index f39d295..0f8bf18 100644 --- a/src-tauri/src/app/menu.rs +++ b/src-tauri/src/app/menu.rs @@ -1,4 +1,5 @@ use crate::{ + app::{cmd, window}, conf::{self, ChatConfJson}, utils, }; @@ -11,8 +12,6 @@ use tauri_plugin_positioner::{on_tray_event, Position, WindowExt}; #[cfg(target_os = "macos")] use tauri::AboutMetadata; -use super::window; - // --- Menu pub fn init() -> Menu { let chat_conf = ChatConfJson::get_chat_conf(); @@ -36,6 +35,11 @@ pub fn init() -> Menu { let stay_on_top = CustomMenuItem::new("stay_on_top".to_string(), "Stay On Top").accelerator("CmdOrCtrl+T"); + let stay_on_top_menu = if chat_conf.stay_on_top { + stay_on_top.selected() + } else { + stay_on_top + }; #[cfg(target_os = "macos")] let titlebar = @@ -51,10 +55,11 @@ pub fn init() -> Menu { let update_silent = CustomMenuItem::new("update_silent".to_string(), "Silent"); let _update_disable = CustomMenuItem::new("update_disable".to_string(), "Disable"); - let stay_on_top_menu = if chat_conf.stay_on_top { - stay_on_top.selected() + let popup_search = CustomMenuItem::new("popup_search".to_string(), "Pop-up Search"); + let popup_search_menu = if chat_conf.popup_search { + popup_search.selected() } else { - stay_on_top + popup_search }; #[cfg(target_os = "macos")] @@ -71,6 +76,15 @@ pub fn init() -> Menu { .accelerator("CmdOrCtrl+Shift+P") .into(), MenuItem::Separator.into(), + stay_on_top_menu.into(), + #[cfg(target_os = "macos")] + titlebar_menu.into(), + #[cfg(target_os = "macos")] + CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(), + CustomMenuItem::new("inject_script".to_string(), "Inject Script") + .accelerator("CmdOrCtrl+J") + .into(), + MenuItem::Separator.into(), Submenu::new( "Theme", Menu::new() @@ -110,15 +124,8 @@ pub fn init() -> Menu { // }) ) .into(), - stay_on_top_menu.into(), - #[cfg(target_os = "macos")] - titlebar_menu.into(), - #[cfg(target_os = "macos")] - CustomMenuItem::new("hide_dock_icon".to_string(), "Hide Dock Icon").into(), - CustomMenuItem::new("inject_script".to_string(), "Inject Script") - .accelerator("CmdOrCtrl+J") - .into(), MenuItem::Separator.into(), + popup_search_menu.into(), CustomMenuItem::new("sync_prompts".to_string(), "Sync Prompts").into(), MenuItem::Separator.into(), CustomMenuItem::new("go_conf".to_string(), "Go to Config") @@ -177,6 +184,8 @@ pub fn init() -> Menu { let window_menu = Submenu::new( "Window", Menu::new() + .add_item(CustomMenuItem::new("dalle2".to_string(), "DALL·E 2")) + .add_native_item(MenuItem::Separator) .add_native_item(MenuItem::Minimize) .add_native_item(MenuItem::Zoom), ); @@ -199,9 +208,9 @@ pub fn init() -> Menu { Menu::new() .add_submenu(app_menu) .add_submenu(preferences_menu) + .add_submenu(window_menu) .add_submenu(edit_menu) .add_submenu(view_menu) - .add_submenu(window_menu) .add_submenu(help_menu) } @@ -209,12 +218,9 @@ pub fn init() -> Menu { pub fn menu_handler(event: WindowMenuEvent) { let win = Some(event.window()).unwrap(); let app = win.app_handle(); - let state: tauri::State = app.state(); let script_path = utils::script_path().to_string_lossy().to_string(); let menu_id = event.menu_item_id(); - - let core_window = app.get_window("core").unwrap(); - let menu_handle = core_window.menu_handle(); + let menu_handle = win.menu_handle(); match menu_id { // App @@ -227,7 +233,7 @@ pub fn menu_handler(event: WindowMenuEvent) { ); } "check_update" => { - utils::run_check_update(app, false).unwrap(); + utils::run_check_update(app, false, None); } // Preferences "control_center" => window::control_window(&app), @@ -236,6 +242,18 @@ pub fn menu_handler(event: WindowMenuEvent) { "go_conf" => utils::open_file(utils::chat_root()), "clear_conf" => utils::clear_conf(&app), "awesome" => open(&app, conf::AWESOME_URL.to_string()), + "popup_search" => { + let chat_conf = conf::ChatConfJson::get_chat_conf(); + let popup_search = !chat_conf.popup_search; + menu_handle + .get_item(menu_id) + .set_selected(popup_search) + .unwrap(); + ChatConfJson::amend(&serde_json::json!({ "popup_search": popup_search }), None) + .unwrap(); + cmd::window_reload(app.clone(), "core"); + cmd::window_reload(app, "tray"); + } "sync_prompts" => { tauri::api::dialog::ask( app.get_window("core").as_ref(), @@ -272,7 +290,8 @@ pub fn menu_handler(event: WindowMenuEvent) { ChatConfJson::amend(&serde_json::json!({ "theme": theme }), Some(app)).unwrap(); } "update_prompt" | "update_silent" | "update_disable" => { - for id in ["update_prompt", "update_silent", "update_disable"] { + // for id in ["update_prompt", "update_silent", "update_disable"] { + for id in ["update_prompt", "update_silent"] { menu_handle.get_item(id).set_selected(false).unwrap(); } let auto_update = match menu_id { @@ -301,19 +320,22 @@ pub fn menu_handler(event: WindowMenuEvent) { ChatConfJson::amend(&serde_json::json!({ "auto_update": auto_update }), None).unwrap(); } "stay_on_top" => { - let mut stay_on_top = state.stay_on_top.lock().unwrap(); - *stay_on_top = !*stay_on_top; + let chat_conf = conf::ChatConfJson::get_chat_conf(); + let stay_on_top = !chat_conf.stay_on_top; menu_handle .get_item(menu_id) - .set_selected(*stay_on_top) + .set_selected(stay_on_top) .unwrap(); - win.set_always_on_top(*stay_on_top).unwrap(); - ChatConfJson::amend(&serde_json::json!({ "stay_on_top": *stay_on_top }), None).unwrap(); + win.set_always_on_top(stay_on_top).unwrap(); + ChatConfJson::amend(&serde_json::json!({ "stay_on_top": stay_on_top }), None).unwrap(); } + // Window + "dalle2" => window::dalle2_window(&app, None, None, Some(false)), // View "reload" => win.eval("window.location.reload()").unwrap(), "go_back" => win.eval("window.history.go(-1)").unwrap(), "go_forward" => win.eval("window.history.go(1)").unwrap(), + // core: document.querySelector('main .overflow-y-auto') "scroll_top" => win .eval( r#"window.scroll({ @@ -346,12 +368,13 @@ pub fn menu_handler(event: WindowMenuEvent) { // --- SystemTray Menu pub fn tray_menu() -> SystemTray { if cfg!(target_os = "macos") { - return SystemTray::new().with_menu( + SystemTray::new().with_menu( SystemTrayMenu::new() .add_item(CustomMenuItem::new( "control_center".to_string(), "Control Center", )) + .add_native_item(SystemTrayMenuItem::Separator) .add_item(CustomMenuItem::new( "show_dock_icon".to_string(), "Show Dock Icon", @@ -360,20 +383,22 @@ pub fn tray_menu() -> SystemTray { "hide_dock_icon".to_string(), "Hide Dock Icon", )) + .add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT")) .add_native_item(SystemTrayMenuItem::Separator) .add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")), - ); + ) + } else { + SystemTray::new().with_menu( + SystemTrayMenu::new() + .add_item(CustomMenuItem::new( + "control_center".to_string(), + "Control Center", + )) + .add_item(CustomMenuItem::new("show_core".to_string(), "Show ChatGPT")) + .add_native_item(SystemTrayMenuItem::Separator) + .add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")), + ) } - - SystemTray::new().with_menu( - SystemTrayMenu::new() - .add_item(CustomMenuItem::new( - "control_center".to_string(), - "Control Center", - )) - .add_native_item(SystemTrayMenuItem::Separator) - .add_item(CustomMenuItem::new("quit".to_string(), "Quit ChatGPT")), - ) } // --- SystemTray Event @@ -414,6 +439,15 @@ pub fn tray_handler(handle: &AppHandle, event: SystemTrayEvent) { .unwrap(); } } + "show_core" => { + let core_win = app.get_window("core").unwrap(); + let tray_win = app.get_window("tray").unwrap(); + if !core_win.is_visible().unwrap() { + core_win.show().unwrap(); + core_win.set_focus().unwrap(); + tray_win.hide().unwrap(); + } + } "quit" => std::process::exit(0), _ => (), }, diff --git a/src-tauri/src/app/setup.rs b/src-tauri/src/app/setup.rs index 8f37981..ca3c0c4 100644 --- a/src-tauri/src/app/setup.rs +++ b/src-tauri/src/app/setup.rs @@ -10,7 +10,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box let theme = ChatConfJson::theme(); let handle = app.app_handle(); - tokio::spawn(async move { + tauri::async_runtime::spawn(async move { window::tray_window(&handle); }); @@ -49,7 +49,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box app.set_activation_policy(tauri::ActivationPolicy::Accessory); } else { let app = app.handle(); - tokio::spawn(async move { + tauri::async_runtime::spawn(async move { #[cfg(target_os = "macos")] WindowBuilder::new(&app, "core", WindowUrl::App(url.into())) .title("ChatGPT") @@ -61,9 +61,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box .always_on_top(chat_conf.stay_on_top) .title_bar_style(ChatConfJson::titlebar()) .initialization_script(&utils::user_script()) - .initialization_script(include_str!("../assets/html2canvas.js")) - .initialization_script(include_str!("../assets/jspdf.js")) + .initialization_script(include_str!("../vendors/floating-ui-core.js")) + .initialization_script(include_str!("../vendors/floating-ui-dom.js")) + .initialization_script(include_str!("../vendors/html2canvas.js")) + .initialization_script(include_str!("../vendors/jspdf.js")) .initialization_script(include_str!("../assets/core.js")) + .initialization_script(include_str!("../assets/popup.core.js")) .initialization_script(include_str!("../assets/export.js")) .initialization_script(include_str!("../assets/cmd.js")) .user_agent(&chat_conf.ua_window) @@ -79,9 +82,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box .theme(theme) .always_on_top(chat_conf.stay_on_top) .initialization_script(&utils::user_script()) - .initialization_script(include_str!("../assets/html2canvas.js")) - .initialization_script(include_str!("../assets/jspdf.js")) + .initialization_script(include_str!("../vendors/floating-ui-core.js")) + .initialization_script(include_str!("../vendors/floating-ui-dom.js")) + .initialization_script(include_str!("../vendors/html2canvas.js")) + .initialization_script(include_str!("../vendors/jspdf.js")) .initialization_script(include_str!("../assets/core.js")) + .initialization_script(include_str!("../assets/popup.core.js")) .initialization_script(include_str!("../assets/export.js")) .initialization_script(include_str!("../assets/cmd.js")) .user_agent(&chat_conf.ua_window) @@ -89,10 +95,12 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box .unwrap(); }); } + // auto_update if chat_conf.auto_update != "Disable" { + info!("stepup::run_check_update"); let app = app.handle(); - utils::run_check_update(app, chat_conf.auto_update == "Silent").unwrap(); + utils::run_check_update(app, chat_conf.auto_update == "Silent", None); } Ok(()) diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs index 546be04..58ca282 100644 --- a/src-tauri/src/app/window.rs +++ b/src-tauri/src/app/window.rs @@ -1,12 +1,14 @@ use crate::{conf, utils}; -use tauri::{utils::config::WindowUrl, window::WindowBuilder}; +use log::info; +use std::time::SystemTime; +use tauri::{utils::config::WindowUrl, window::WindowBuilder, Manager}; pub fn tray_window(handle: &tauri::AppHandle) { let chat_conf = conf::ChatConfJson::get_chat_conf(); let theme = conf::ChatConfJson::theme(); let app = handle.clone(); - tokio::spawn(async move { + tauri::async_runtime::spawn(async move { WindowBuilder::new(&app, "tray", WindowUrl::App(chat_conf.origin.into())) .title("ChatGPT") .resizable(false) @@ -16,8 +18,11 @@ pub fn tray_window(handle: &tauri::AppHandle) { .always_on_top(true) .theme(theme) .initialization_script(&utils::user_script()) + .initialization_script(include_str!("../vendors/floating-ui-core.js")) + .initialization_script(include_str!("../vendors/floating-ui-dom.js")) .initialization_script(include_str!("../assets/core.js")) .initialization_script(include_str!("../assets/cmd.js")) + .initialization_script(include_str!("../assets/popup.core.js")) .user_agent(&chat_conf.ua_tray) .build() .unwrap() @@ -26,16 +31,77 @@ pub fn tray_window(handle: &tauri::AppHandle) { }); } -pub fn control_window(handle: &tauri::AppHandle) { +pub fn dalle2_window( + handle: &tauri::AppHandle, + query: Option, + title: Option, + is_new: Option, +) { + info!("dalle2_query: {:?}", query); + let theme = conf::ChatConfJson::theme(); let app = handle.clone(); - tokio::spawn(async move { - WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into())) - .title("Control Center") + + let query = if query.is_some() { + format!( + "window.addEventListener('DOMContentLoaded', function() {{\nwindow.__CHATGPT_QUERY__='{}';\n}})", + query.unwrap() + ) + } else { + "".to_string() + }; + + let label = if is_new.unwrap_or(true) { + let timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); + format!("dalle2_{}", timestamp) + } else { + "dalle2".to_string() + }; + + if app.get_window("dalle2").is_none() { + tauri::async_runtime::spawn(async move { + WindowBuilder::new( + &app, + label, + WindowUrl::App("https://labs.openai.com".into()), + ) + .title(title.unwrap_or_else(|| "DALL·E 2".to_string())) .resizable(true) .fullscreen(false) .inner_size(800.0, 600.0) - .min_inner_size(800.0, 600.0) + .always_on_top(false) + .theme(theme) + .initialization_script(include_str!("../assets/core.js")) + .initialization_script(&query) + .initialization_script(include_str!("../assets/dalle2.js")) .build() .unwrap(); + }); + } else { + let dalle2_win = app.get_window("dalle2").unwrap(); + dalle2_win.show().unwrap(); + dalle2_win.set_focus().unwrap(); + } +} + +pub fn control_window(handle: &tauri::AppHandle) { + let app = handle.clone(); + tauri::async_runtime::spawn(async move { + if app.app_handle().get_window("main").is_none() { + WindowBuilder::new(&app, "main", WindowUrl::App("index.html".into())) + .title("Control Center") + .resizable(true) + .fullscreen(false) + .inner_size(800.0, 600.0) + .min_inner_size(800.0, 600.0) + .build() + .unwrap(); + } else { + let main_win = app.app_handle().get_window("main").unwrap(); + main_win.show().unwrap(); + main_win.set_focus().unwrap(); + } }); } diff --git a/src-tauri/src/assets/cmd.js b/src-tauri/src/assets/cmd.js index 6c712d1..4588e5a 100644 --- a/src-tauri/src/assets/cmd.js +++ b/src-tauri/src/assets/cmd.js @@ -75,6 +75,11 @@ function init() { width: 24px; height: 24px; } + @media screen and (max-width: 767px) { + #download-png-button, #download-pdf-button, #download-html-button { + display: none; + } + } `; document.head.append(styleDom); diff --git a/src-tauri/src/assets/core.js b/src-tauri/src/assets/core.js index 8f50323..335daa8 100644 --- a/src-tauri/src/assets/core.js +++ b/src-tauri/src/assets/core.js @@ -71,6 +71,7 @@ async function init() { document.addEventListener("click", (e) => { const origin = e.target.closest("a"); + if (!origin.target) return; if (origin && origin.href && origin.target !== '_self') { invoke('open_link', { url: origin.href }); } diff --git a/src-tauri/src/assets/dalle2.js b/src-tauri/src/assets/dalle2.js new file mode 100644 index 0000000..e95d4c0 --- /dev/null +++ b/src-tauri/src/assets/dalle2.js @@ -0,0 +1,40 @@ +// *** Core Script - DALL·E 2 *** + +async function init() { + document.addEventListener("click", (e) => { + const origin = e.target.closest("a"); + if (!origin.target) return; + if (origin && origin.href && origin.target !== '_self') { + if (/\/(login|signup)$/.test(window.location.href)) { + origin.target = '_self'; + } else { + invoke('open_link', { url: origin.href }); + } + } + }); + + if (window.searchInterval) { + clearInterval(window.searchInterval); + } + + window.searchInterval = setInterval(() => { + const searchInput = document.querySelector('.image-prompt-form-wrapper form>.text-input'); + if (searchInput) { + clearInterval(window.searchInterval); + + if (!window.__CHATGPT_QUERY__) return; + const query = decodeURIComponent(window.__CHATGPT_QUERY__); + searchInput.focus(); + searchInput.value = query; + } + }, 200) +} + +if ( + document.readyState === "complete" || + document.readyState === "interactive" +) { + init(); +} else { + document.addEventListener("DOMContentLoaded", init); +} diff --git a/src-tauri/src/assets/popup.core.js b/src-tauri/src/assets/popup.core.js new file mode 100644 index 0000000..3eb7b02 --- /dev/null +++ b/src-tauri/src/assets/popup.core.js @@ -0,0 +1,84 @@ +// *** Core Script - DALL·E 2 Core *** + +async function init() { + const chatConf = await invoke('get_chat_conf') || {}; + if (!chatConf.popup_search) return; + if (!window.FloatingUIDOM) return; + + const styleDom = document.createElement('style'); + styleDom.innerHTML = ` + #chagpt-selection-menu { + display: none; + width: max-content; + position: absolute; + top: 0; + left: 0; + background: #4a4a4a; + color: white; + font-weight: bold; + padding: 5px 8px; + border-radius: 4px; + font-size: 12px; + cursor: pointer; + } + `; + document.head.append(styleDom); + + const selectionMenu = document.createElement('div'); + selectionMenu.id = 'chagpt-selection-menu'; + selectionMenu.innerHTML = 'DALL·E 2'; + document.body.appendChild(selectionMenu); + const { computePosition, flip, offset, shift } = window.FloatingUIDOM; + + document.body.addEventListener('mousedown', async (e) => { + if (e.target.id === 'chagpt-selection-menu') { + await invoke('dalle2_window', { query: encodeURIComponent(window.__DALLE2_CONTENT__) }); + } else { + delete window.__DALLE2_CONTENT__; + } + }); + + document.body.addEventListener("mouseup", async (e) => { + selectionMenu.style.display = 'none'; + const selection = window.getSelection(); + window.__DALLE2_CONTENT__ = selection.toString().trim(); + + if (!window.__DALLE2_CONTENT__) return; + + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + const rect = range.getClientRects()[0]; + + const rootEl = document.createElement('div'); + rootEl.style.top = `${rect.top}px`; + rootEl.style.position = 'fixed'; + rootEl.style.left = `${rect.left}px`; + document.body.appendChild(rootEl); + + selectionMenu.style.display = 'block'; + computePosition(rootEl, selectionMenu, { + placement: 'top', + middleware: [ + flip(), + offset(5), + shift({ padding: 5 }) + ] + }).then(({x, y}) => { + Object.assign(selectionMenu.style, { + left: `${x}px`, + top: `${y}px`, + }); + }); + } + }); + +} + +if ( + document.readyState === "complete" || + document.readyState === "interactive" +) { + init(); +} else { + document.addEventListener("DOMContentLoaded", init); +} \ No newline at end of file diff --git a/src-tauri/src/conf.rs b/src-tauri/src/conf.rs index f71a188..e2ba14a 100644 --- a/src-tauri/src/conf.rs +++ b/src-tauri/src/conf.rs @@ -2,7 +2,7 @@ use crate::utils::{chat_root, create_file, exists}; use anyhow::Result; use log::info; use serde_json::Value; -use std::{collections::BTreeMap, fs, path::PathBuf, sync::Mutex}; +use std::{collections::BTreeMap, fs, path::PathBuf}; use tauri::{Manager, Theme}; #[cfg(target_os = "macos")] @@ -21,6 +21,7 @@ pub const DEFAULT_CHAT_CONF: &str = r#"{ "auto_update": "Prompt", "theme": "Light", "titlebar": true, + "popup_search": true, "global_shortcut": "", "hide_dock_icon": false, "default_origin": "https://chat.openai.com", @@ -33,6 +34,7 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{ "auto_update": "Prompt", "theme": "Light", "titlebar": false, + "popup_search": true, "global_shortcut": "", "hide_dock_icon": false, "default_origin": "https://chat.openai.com", @@ -41,18 +43,6 @@ pub const DEFAULT_CHAT_CONF_MAC: &str = r#"{ "ua_tray": "" }"#; -pub struct ChatState { - pub stay_on_top: Mutex, -} - -impl ChatState { - pub fn default(chat_conf: ChatConfJson) -> Self { - ChatState { - stay_on_top: Mutex::new(chat_conf.stay_on_top), - } - } -} - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct ChatConfJson { // support macOS only @@ -63,6 +53,7 @@ pub struct ChatConfJson { pub theme: String, // auto update policy, Prompt/Silent/Disable pub auto_update: String, + pub popup_search: bool, pub stay_on_top: bool, pub default_origin: String, pub origin: String, diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index fc218f5..5d9db81 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -8,8 +8,9 @@ mod conf; mod utils; use app::{cmd, fs_extra, menu, setup}; -use conf::{ChatConfJson, ChatState}; +use conf::ChatConfJson; use tauri::api::path; +use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_log::{ fern::colors::{Color, ColoredLevelConfig}, LogTarget, LoggerBuilder, @@ -20,7 +21,6 @@ async fn main() { ChatConfJson::init(); // If the file does not exist, creating the file will block menu synchronization utils::create_chatgpt_prompts(); - let chat_conf = ChatConfJson::get_chat_conf(); let context = tauri::generate_context!(); let colors = ColoredLevelConfig { error: Color::Red, @@ -34,11 +34,7 @@ async fn main() { // https://github.com/tauri-apps/tauri/pull/2736 .plugin( LoggerBuilder::new() - .level(if cfg!(debug_assertions) { - log::LevelFilter::Debug - } else { - log::LevelFilter::Trace - }) + .level(log::LevelFilter::Debug) .with_colors(colors) .targets([ // LogTarget::LogDir, @@ -49,7 +45,6 @@ async fn main() { ]) .build(), ) - .manage(ChatState::default(chat_conf)) .invoke_handler(tauri::generate_handler![ cmd::drag_window, cmd::fullscreen, @@ -68,11 +63,16 @@ async fn main() { cmd::sync_prompts, cmd::sync_user_prompts, cmd::window_reload, + cmd::dalle2_window, cmd::cmd_list, fs_extra::metadata, ]) .setup(setup::init) .plugin(tauri_plugin_positioner::init()) + .plugin(tauri_plugin_autostart::init( + MacosLauncher::LaunchAgent, + None, + )) .menu(menu::init()) .system_tray(menu::tray_menu()) .on_menu_event(menu::menu_handler) @@ -81,13 +81,18 @@ async fn main() { // https://github.com/tauri-apps/tauri/discussions/2684 if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() { let win = event.window(); - if win.label() == "main" { - win.close().unwrap(); - } else { + if win.label() == "core" { // TODO: https://github.com/tauri-apps/tauri/issues/3084 // event.window().hide().unwrap(); // https://github.com/tauri-apps/tao/pull/517 + #[cfg(target_os = "macos")] event.window().minimize().unwrap(); + + // fix: https://github.com/lencx/ChatGPT/issues/93 + #[cfg(not(target_os = "macos"))] + event.window().hide().unwrap(); + } else { + win.close().unwrap(); } api.prevent_close(); } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index a23c668..608936f 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -130,7 +130,8 @@ pub async fn get_data( } } -pub fn run_check_update(app: AppHandle, silent: bool) -> Result<()> { +pub fn run_check_update(app: AppHandle, silent: bool, has_msg: Option) { + info!("run_check_update: silent={} has_msg={:?}", silent, has_msg); tauri::async_runtime::spawn(async move { let result = app.updater().check().await; let update_resp = result.unwrap(); @@ -144,15 +145,23 @@ pub fn run_check_update(app: AppHandle, silent: bool) -> Result<()> { prompt_for_install(app, update_resp).await.unwrap(); }); } + } else if let Some(v) = has_msg { + if v { + tauri::api::dialog::message( + app.app_handle().get_window("core").as_ref(), + "ChatGPT", + "Your ChatGPT is up to date", + ); + } } }); - Ok(()) } // Copy private api in tauri/updater/mod.rs. TODO: refactor to public api // Prompt a dialog asking if the user want to install the new version // Maybe we should add an option to customize it in future versions. pub async fn prompt_for_install(app: AppHandle, update: UpdateResponse) -> Result<()> { + info!("prompt_for_install"); let windows = app.windows(); let parent_window = windows.values().next(); let package_info = app.package_info().clone(); @@ -199,6 +208,7 @@ Release Notes: } pub async fn silent_install(app: AppHandle, update: UpdateResponse) -> Result<()> { + info!("silent_install"); let windows = app.windows(); let parent_window = windows.values().next(); diff --git a/src-tauri/src/vendors/floating-ui-core.js b/src-tauri/src/vendors/floating-ui-core.js new file mode 100644 index 0000000..a0f787b --- /dev/null +++ b/src-tauri/src/vendors/floating-ui-core.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).FloatingUICore={})}(this,(function(t){"use strict";function e(t){return t.split("-")[1]}function n(t){return"y"===t?"height":"width"}function i(t){return t.split("-")[0]}function o(t){return["top","bottom"].includes(i(t))?"x":"y"}function r(t,r,a){let{reference:l,floating:s}=t;const f=l.x+l.width/2-s.width/2,c=l.y+l.height/2-s.height/2,u=o(r),m=n(u),d=l[m]/2-s[m]/2,g="x"===u;let p;switch(i(r)){case"top":p={x:f,y:l.y-s.height};break;case"bottom":p={x:f,y:l.y+l.height};break;case"right":p={x:l.x+l.width,y:c};break;case"left":p={x:l.x-s.width,y:c};break;default:p={x:l.x,y:l.y}}switch(e(r)){case"start":p[u]-=d*(a&&g?-1:1);break;case"end":p[u]+=d*(a&&g?-1:1)}return p}function a(t){return"number"!=typeof t?function(t){return{top:0,right:0,bottom:0,left:0,...t}}(t):{top:t,right:t,bottom:t,left:t}}function l(t){return{...t,top:t.y,left:t.x,right:t.x+t.width,bottom:t.y+t.height}}async function s(t,e){var n;void 0===e&&(e={});const{x:i,y:o,platform:r,rects:s,elements:f,strategy:c}=t,{boundary:u="clippingAncestors",rootBoundary:m="viewport",elementContext:d="floating",altBoundary:g=!1,padding:p=0}=e,h=a(p),y=f[g?"floating"===d?"reference":"floating":d],x=l(await r.getClippingRect({element:null==(n=await(null==r.isElement?void 0:r.isElement(y)))||n?y:y.contextElement||await(null==r.getDocumentElement?void 0:r.getDocumentElement(f.floating)),boundary:u,rootBoundary:m,strategy:c})),w="floating"===d?{...s.floating,x:i,y:o}:s.reference,v=await(null==r.getOffsetParent?void 0:r.getOffsetParent(f.floating)),b=await(null==r.isElement?void 0:r.isElement(v))&&await(null==r.getScale?void 0:r.getScale(v))||{x:1,y:1},R=l(r.convertOffsetParentRelativeRectToViewportRelativeRect?await r.convertOffsetParentRelativeRectToViewportRelativeRect({rect:w,offsetParent:v,strategy:c}):w);return{top:(x.top-R.top+h.top)/b.y,bottom:(R.bottom-x.bottom+h.bottom)/b.y,left:(x.left-R.left+h.left)/b.x,right:(R.right-x.right+h.right)/b.x}}const f=Math.min,c=Math.max;function u(t,e,n){return c(t,f(e,n))}const m=["top","right","bottom","left"],d=m.reduce(((t,e)=>t.concat(e,e+"-start",e+"-end")),[]),g={left:"right",right:"left",bottom:"top",top:"bottom"};function p(t){return t.replace(/left|right|bottom|top/g,(t=>g[t]))}function h(t,i,r){void 0===r&&(r=!1);const a=e(t),l=o(t),s=n(l);let f="x"===l?a===(r?"end":"start")?"right":"left":"start"===a?"bottom":"top";return i.reference[s]>i.floating[s]&&(f=p(f)),{main:f,cross:p(f)}}const y={start:"end",end:"start"};function x(t){return t.replace(/start|end/g,(t=>y[t]))}function w(t,e){return{top:t.top-e.height,right:t.right-e.width,bottom:t.bottom-e.height,left:t.left-e.width}}function v(t){return m.some((e=>t[e]>=0))}function b(t){return"x"===t?"y":"x"}t.arrow=t=>({name:"arrow",options:t,async fn(i){const{element:r,padding:l=0}=t||{},{x:s,y:f,placement:c,rects:m,platform:d}=i;if(null==r)return{};const g=a(l),p={x:s,y:f},h=o(c),y=n(h),x=await d.getDimensions(r),w="y"===h?"top":"left",v="y"===h?"bottom":"right",b=m.reference[y]+m.reference[h]-p[h]-m.floating[y],R=p[h]-m.reference[h],A=await(null==d.getOffsetParent?void 0:d.getOffsetParent(r));let P=A?"y"===h?A.clientHeight||0:A.clientWidth||0:0;0===P&&(P=m.floating[y]);const T=b/2-R/2,O=g[w],D=P-x[y]-g[v],E=P/2-x[y]/2+T,L=u(O,E,D),k=null!=e(c)&&E!=L&&m.reference[y]/2-(Ee(n)===t)),...o.filter((n=>e(n)!==t))]:o.filter((t=>i(t)===t))).filter((i=>!t||e(i)===t||!!n&&x(i)!==i))}(g||null,y,p):p,b=await s(n,w),R=(null==(o=f.autoPlacement)?void 0:o.index)||0,A=v[R];if(null==A)return{};const{main:P,cross:T}=h(A,l,await(null==u.isRTL?void 0:u.isRTL(m.floating)));if(c!==A)return{reset:{placement:v[0]}};const O=[b[i(A)],b[P],b[T]],D=[...(null==(r=f.autoPlacement)?void 0:r.overflows)||[],{placement:A,overflows:O}],E=v[R+1];if(E)return{data:{index:R+1,overflows:D},reset:{placement:E}};const L=D.slice().sort(((t,e)=>t.overflows[0]-e.overflows[0])),k=null==(a=L.find((t=>{let{overflows:e}=t;return e.every((t=>t<=0))})))?void 0:a.placement,C=k||L[0].placement;return C!==c?{data:{index:R+1,overflows:D},reset:{placement:C}}:{}}}},t.computePosition=async(t,e,n)=>{const{placement:i="bottom",strategy:o="absolute",middleware:a=[],platform:l}=n,s=a.filter(Boolean),f=await(null==l.isRTL?void 0:l.isRTL(e));let c=await l.getElementRects({reference:t,floating:e,strategy:o}),{x:u,y:m}=r(c,i,f),d=i,g={},p=0;for(let n=0;nt+"-"+a)),n&&(l=l.concat(l.map(x)))),l}(f,v,w,P));const O=[f,...T],D=await s(n,b),E=[];let L=(null==(o=a.flip)?void 0:o.overflows)||[];if(m&&E.push(D[R]),d){const{main:t,cross:e}=h(r,l,P);E.push(D[t],D[e])}if(L=[...L,{placement:r,overflows:E}],!E.every((t=>t<=0))){var k;const t=((null==(k=a.flip)?void 0:k.index)||0)+1,e=O[t];if(e)return{data:{index:t,overflows:L},reset:{placement:e}};let n="bottom";switch(y){case"bestFit":{var C;const t=null==(C=L.map((t=>[t,t.overflows.filter((t=>t>0)).reduce(((t,e)=>t+e),0)])).sort(((t,e)=>t[1]-e[1]))[0])?void 0:C[0].placement;t&&(n=t);break}case"initialPlacement":n=f}if(r!==n)return{reset:{placement:n}}}return{}}}},t.hide=function(t){return void 0===t&&(t={}),{name:"hide",options:t,async fn(e){const{strategy:n="referenceHidden",...i}=t,{rects:o}=e;switch(n){case"referenceHidden":{const t=w(await s(e,{...i,elementContext:"reference"}),o.reference);return{data:{referenceHiddenOffsets:t,referenceHidden:v(t)}}}case"escaped":{const t=w(await s(e,{...i,altBoundary:!0}),o.floating);return{data:{escapedOffsets:t,escaped:v(t)}}}default:return{}}}}},t.inline=function(t){return void 0===t&&(t={}),{name:"inline",options:t,async fn(e){const{placement:n,elements:r,rects:s,platform:u,strategy:m}=e,{padding:d=2,x:g,y:p}=t,h=l(u.convertOffsetParentRelativeRectToViewportRelativeRect?await u.convertOffsetParentRelativeRectToViewportRelativeRect({rect:s.reference,offsetParent:await(null==u.getOffsetParent?void 0:u.getOffsetParent(r.floating)),strategy:m}):s.reference),y=await(null==u.getClientRects?void 0:u.getClientRects(r.reference))||[],x=a(d);const w=await u.getElementRects({reference:{getBoundingClientRect:function(){if(2===y.length&&y[0].left>y[1].right&&null!=g&&null!=p)return y.find((t=>g>t.left-x.left&&gt.top-x.top&&p=2){if("x"===o(n)){const t=y[0],e=y[y.length-1],o="top"===i(n),r=t.top,a=e.bottom,l=o?t.left:e.left,s=o?t.right:e.right;return{top:r,bottom:a,left:l,right:s,width:s-l,height:a-r,x:l,y:r}}const t="left"===i(n),e=c(...y.map((t=>t.right))),r=f(...y.map((t=>t.left))),a=y.filter((n=>t?n.left===r:n.right===e)),l=a[0].top,s=a[a.length-1].bottom;return{top:l,bottom:s,left:r,right:e,width:e-r,height:s-l,x:r,y:l}}return h}},floating:r.floating,strategy:m});return s.reference.x!==w.reference.x||s.reference.y!==w.reference.y||s.reference.width!==w.reference.width||s.reference.height!==w.reference.height?{reset:{rects:w}}:{}}}},t.limitShift=function(t){return void 0===t&&(t={}),{options:t,fn(e){const{x:n,y:r,placement:a,rects:l,middlewareData:s}=e,{offset:f=0,mainAxis:c=!0,crossAxis:u=!0}=t,m={x:n,y:r},d=o(a),g=b(d);let p=m[d],h=m[g];const y="function"==typeof f?f(e):f,x="number"==typeof y?{mainAxis:y,crossAxis:0}:{mainAxis:0,crossAxis:0,...y};if(c){const t="y"===d?"height":"width",e=l.reference[d]-l.floating[t]+x.mainAxis,n=l.reference[d]+l.reference[t]-x.mainAxis;pn&&(p=n)}if(u){var w,v;const t="y"===d?"width":"height",e=["top","left"].includes(i(a)),n=l.reference[g]-l.floating[t]+(e&&(null==(w=s.offset)?void 0:w[g])||0)+(e?0:x.crossAxis),o=l.reference[g]+l.reference[t]+(e?0:(null==(v=s.offset)?void 0:v[g])||0)-(e?x.crossAxis:0);ho&&(h=o)}return{[d]:p,[g]:h}}}},t.offset=function(t){return void 0===t&&(t=0),{name:"offset",options:t,async fn(n){const{x:r,y:a}=n,l=await async function(t,n){const{placement:r,platform:a,elements:l}=t,s=await(null==a.isRTL?void 0:a.isRTL(l.floating)),f=i(r),c=e(r),u="x"===o(r),m=["left","top"].includes(f)?-1:1,d=s&&u?-1:1,g="function"==typeof n?n(t):n;let{mainAxis:p,crossAxis:h,alignmentAxis:y}="number"==typeof g?{mainAxis:g,crossAxis:0,alignmentAxis:null}:{mainAxis:0,crossAxis:0,alignmentAxis:null,...g};return c&&"number"==typeof y&&(h="end"===c?-1*y:y),u?{x:h*d,y:p*m}:{x:p*m,y:h*d}}(n,t);return{x:r+l.x,y:a+l.y,data:l}}}},t.rectToClientRect=l,t.shift=function(t){return void 0===t&&(t={}),{name:"shift",options:t,async fn(e){const{x:n,y:r,placement:a}=e,{mainAxis:l=!0,crossAxis:f=!1,limiter:c={fn:t=>{let{x:e,y:n}=t;return{x:e,y:n}}},...m}=t,d={x:n,y:r},g=await s(e,m),p=o(i(a)),h=b(p);let y=d[p],x=d[h];if(l){const t="y"===p?"bottom":"right";y=u(y+g["y"===p?"top":"left"],y,y-g[t])}if(f){const t="y"===h?"bottom":"right";x=u(x+g["y"===h?"top":"left"],x,x-g[t])}const w=c.fn({...e,[p]:y,[h]:x});return{...w,data:{x:w.x-n,y:w.y-r}}}}},t.size=function(t){return void 0===t&&(t={}),{name:"size",options:t,async fn(n){const{placement:o,rects:r,platform:a,elements:l}=n,{apply:f=(()=>{}),...u}=t,m=await s(n,u),d=i(o),g=e(o);let p,h;"top"===d||"bottom"===d?(p=d,h=g===(await(null==a.isRTL?void 0:a.isRTL(l.floating))?"start":"end")?"left":"right"):(h=d,p="end"===g?"top":"bottom");const y=c(m.left,0),x=c(m.right,0),w=c(m.top,0),v=c(m.bottom,0),b={availableHeight:r.floating.height-(["left","right"].includes(o)?2*(0!==w||0!==v?w+v:c(m.top,m.bottom)):m[p]),availableWidth:r.floating.width-(["top","bottom"].includes(o)?2*(0!==y||0!==x?y+x:c(m.left,m.right)):m[h])};await f({...n,...b});const R=await a.getDimensions(l.floating);return r.floating.width!==R.width||r.floating.height!==R.height?{reset:{rects:!0}}:{}}}},Object.defineProperty(t,"__esModule",{value:!0})})); \ No newline at end of file diff --git a/src-tauri/src/vendors/floating-ui-dom.js b/src-tauri/src/vendors/floating-ui-dom.js new file mode 100644 index 0000000..5c7c9a3 --- /dev/null +++ b/src-tauri/src/vendors/floating-ui-dom.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@floating-ui/core")):"function"==typeof define&&define.amd?define(["exports","@floating-ui/core"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).FloatingUIDOM={},t.FloatingUICore)}(this,(function(t,e){"use strict";function n(t){var e;return(null==(e=t.ownerDocument)?void 0:e.defaultView)||window}function o(t){return n(t).getComputedStyle(t)}function i(t){return s(t)?(t.nodeName||"").toLowerCase():""}let r;function l(){if(r)return r;const t=navigator.userAgentData;return t&&Array.isArray(t.brands)?(r=t.brands.map((t=>t.brand+"/"+t.version)).join(" "),r):navigator.userAgent}function c(t){return t instanceof n(t).HTMLElement}function f(t){return t instanceof n(t).Element}function s(t){return t instanceof n(t).Node}function u(t){if("undefined"==typeof ShadowRoot)return!1;return t instanceof n(t).ShadowRoot||t instanceof ShadowRoot}function a(t){const{overflow:e,overflowX:n,overflowY:i,display:r}=o(t);return/auto|scroll|overlay|hidden|clip/.test(e+i+n)&&!["inline","contents"].includes(r)}function d(t){return["table","td","th"].includes(i(t))}function h(t){const e=/firefox/i.test(l()),n=o(t),i=n.backdropFilter||n.WebkitBackdropFilter;return"none"!==n.transform||"none"!==n.perspective||!!i&&"none"!==i||e&&"filter"===n.willChange||e&&!!n.filter&&"none"!==n.filter||["transform","perspective"].some((t=>n.willChange.includes(t)))||["paint","layout","strict","content"].some((t=>{const e=n.contain;return null!=e&&e.includes(t)}))}function p(){return!/^((?!chrome|android).)*safari/i.test(l())}function g(t){return["html","body","#document"].includes(i(t))}const m=Math.min,y=Math.max,b=Math.round;function w(t){const e=o(t);let n=parseFloat(e.width),i=parseFloat(e.height);const r=t.offsetWidth,l=t.offsetHeight,c=b(n)!==r||b(i)!==l;return c&&(n=r,i=l),{width:n,height:i,fallback:c}}function x(t){return f(t)?t:t.contextElement}const v={x:1,y:1};function L(t){const e=x(t);if(!c(e))return v;const n=e.getBoundingClientRect(),{width:o,height:i,fallback:r}=w(e);let l=(r?b(n.width):n.width)/o,f=(r?b(n.height):n.height)/i;return l&&Number.isFinite(l)||(l=1),f&&Number.isFinite(f)||(f=1),{x:l,y:f}}function T(t,e,o,i){var r,l;void 0===e&&(e=!1),void 0===o&&(o=!1);const c=t.getBoundingClientRect(),s=x(t);let u=v;e&&(i?f(i)&&(u=L(i)):u=L(t));const a=s?n(s):window,d=!p()&&o;let h=(c.left+(d&&(null==(r=a.visualViewport)?void 0:r.offsetLeft)||0))/u.x,g=(c.top+(d&&(null==(l=a.visualViewport)?void 0:l.offsetTop)||0))/u.y,m=c.width/u.x,y=c.height/u.y;if(s){const t=n(s),e=i&&f(i)?n(i):i;let o=t.frameElement;for(;o&&i&&e!==t;){const t=L(o),e=o.getBoundingClientRect(),i=getComputedStyle(o);e.x+=(o.clientLeft+parseFloat(i.paddingLeft))*t.x,e.y+=(o.clientTop+parseFloat(i.paddingTop))*t.y,h*=t.x,g*=t.y,m*=t.x,y*=t.y,h+=e.x,g+=e.y,o=n(o).frameElement}}return{width:m,height:y,top:g,right:h+m,bottom:g+y,left:h,x:h,y:g}}function O(t){return((s(t)?t.ownerDocument:t.document)||window.document).documentElement}function P(t){return f(t)?{scrollLeft:t.scrollLeft,scrollTop:t.scrollTop}:{scrollLeft:t.pageXOffset,scrollTop:t.pageYOffset}}function R(t){return T(O(t)).left+P(t).scrollLeft}function E(t,e,n){const o=c(e),r=O(e),l=T(t,!0,"fixed"===n,e);let f={scrollLeft:0,scrollTop:0};const s={x:0,y:0};if(o||!o&&"fixed"!==n)if(("body"!==i(e)||a(r))&&(f=P(e)),c(e)){const t=T(e,!0);s.x=t.x+e.clientLeft,s.y=t.y+e.clientTop}else r&&(s.x=R(r));return{x:l.left+f.scrollLeft-s.x,y:l.top+f.scrollTop-s.y,width:l.width,height:l.height}}function C(t){if("html"===i(t))return t;const e=t.assignedSlot||t.parentNode||(u(t)?t.host:null)||O(t);return u(e)?e.host:e}function j(t){return c(t)&&"fixed"!==o(t).position?t.offsetParent:null}function F(t){const e=n(t);let r=j(t);for(;r&&d(r)&&"static"===o(r).position;)r=j(r);return r&&("html"===i(r)||"body"===i(r)&&"static"===o(r).position&&!h(r))?e:r||function(t){let e=C(t);for(;c(e)&&!g(e);){if(h(e))return e;e=C(e)}return null}(t)||e}function D(t){const e=C(t);return g(e)?t.ownerDocument.body:c(e)&&a(e)?e:D(e)}function S(t,e){var o;void 0===e&&(e=[]);const i=D(t),r=i===(null==(o=t.ownerDocument)?void 0:o.body),l=n(i);return r?e.concat(l,l.visualViewport||[],a(i)?i:[]):e.concat(i,S(i))}function W(t,i,r){return"viewport"===i?e.rectToClientRect(function(t,e){const o=n(t),i=O(t),r=o.visualViewport;let l=i.clientWidth,c=i.clientHeight,f=0,s=0;if(r){l=r.width,c=r.height;const t=p();(t||!t&&"fixed"===e)&&(f=r.offsetLeft,s=r.offsetTop)}return{width:l,height:c,x:f,y:s}}(t,r)):f(i)?function(t,e){const n=T(t,!0,"fixed"===e),o=n.top+t.clientTop,i=n.left+t.clientLeft,r=c(t)?L(t):{x:1,y:1},l=t.clientWidth*r.x,f=t.clientHeight*r.y,s=i*r.x,u=o*r.y;return{top:u,left:s,right:s+l,bottom:u+f,x:s,y:u,width:l,height:f}}(i,r):e.rectToClientRect(function(t){var e;const n=O(t),i=P(t),r=null==(e=t.ownerDocument)?void 0:e.body,l=y(n.scrollWidth,n.clientWidth,r?r.scrollWidth:0,r?r.clientWidth:0),c=y(n.scrollHeight,n.clientHeight,r?r.scrollHeight:0,r?r.clientHeight:0);let f=-i.scrollLeft+R(t);const s=-i.scrollTop;return"rtl"===o(r||n).direction&&(f+=y(n.clientWidth,r?r.clientWidth:0)-l),{width:l,height:c,x:f,y:s}}(O(t)))}const A={getClippingRect:function(t){let{element:e,boundary:n,rootBoundary:r,strategy:l}=t;const c="clippingAncestors"===n?function(t,e){const n=e.get(t);if(n)return n;let r=S(t).filter((t=>f(t)&&"body"!==i(t))),l=null;const c="fixed"===o(t).position;let s=c?C(t):t;for(;f(s)&&!g(s);){const t=o(s),e=h(s);(c?e||l:e||"static"!==t.position||!l||!["absolute","fixed"].includes(l.position))?l=t:r=r.filter((t=>t!==s)),s=C(s)}return e.set(t,r),r}(e,this._c):[].concat(n),s=[...c,r],u=s[0],a=s.reduce(((t,n)=>{const o=W(e,n,l);return t.top=y(o.top,t.top),t.right=m(o.right,t.right),t.bottom=m(o.bottom,t.bottom),t.left=y(o.left,t.left),t}),W(e,u,l));return{width:a.right-a.left,height:a.bottom-a.top,x:a.left,y:a.top}},convertOffsetParentRelativeRectToViewportRelativeRect:function(t){let{rect:e,offsetParent:n,strategy:o}=t;const r=c(n),l=O(n);if(n===l)return e;let f={scrollLeft:0,scrollTop:0},s={x:1,y:1};const u={x:0,y:0};if((r||!r&&"fixed"!==o)&&(("body"!==i(n)||a(l))&&(f=P(n)),c(n))){const t=T(n);s=L(n),u.x=t.x+n.clientLeft,u.y=t.y+n.clientTop}return{width:e.width*s.x,height:e.height*s.y,x:e.x*s.x-f.scrollLeft*s.x+u.x,y:e.y*s.y-f.scrollTop*s.y+u.y}},isElement:f,getDimensions:function(t){return w(t)},getOffsetParent:F,getDocumentElement:O,getScale:L,async getElementRects(t){let{reference:e,floating:n,strategy:o}=t;const i=this.getOffsetParent||F,r=this.getDimensions;return{reference:E(e,await i(n),o),floating:{x:0,y:0,...await r(n)}}},getClientRects:t=>Array.from(t.getClientRects()),isRTL:t=>"rtl"===o(t).direction};Object.defineProperty(t,"arrow",{enumerable:!0,get:function(){return e.arrow}}),Object.defineProperty(t,"autoPlacement",{enumerable:!0,get:function(){return e.autoPlacement}}),Object.defineProperty(t,"detectOverflow",{enumerable:!0,get:function(){return e.detectOverflow}}),Object.defineProperty(t,"flip",{enumerable:!0,get:function(){return e.flip}}),Object.defineProperty(t,"hide",{enumerable:!0,get:function(){return e.hide}}),Object.defineProperty(t,"inline",{enumerable:!0,get:function(){return e.inline}}),Object.defineProperty(t,"limitShift",{enumerable:!0,get:function(){return e.limitShift}}),Object.defineProperty(t,"offset",{enumerable:!0,get:function(){return e.offset}}),Object.defineProperty(t,"shift",{enumerable:!0,get:function(){return e.shift}}),Object.defineProperty(t,"size",{enumerable:!0,get:function(){return e.size}}),t.autoUpdate=function(t,e,n,o){void 0===o&&(o={});const{ancestorScroll:i=!0,ancestorResize:r=!0,elementResize:l=!0,animationFrame:c=!1}=o,s=i&&!c,u=s||r?[...f(t)?S(t):t.contextElement?S(t.contextElement):[],...S(e)]:[];u.forEach((t=>{s&&t.addEventListener("scroll",n,{passive:!0}),r&&t.addEventListener("resize",n)}));let a,d=null;if(l){let o=!0;d=new ResizeObserver((()=>{o||n(),o=!1})),f(t)&&!c&&d.observe(t),f(t)||!t.contextElement||c||d.observe(t.contextElement),d.observe(e)}let h=c?T(t):null;return c&&function e(){const o=T(t);!h||o.x===h.x&&o.y===h.y&&o.width===h.width&&o.height===h.height||n();h=o,a=requestAnimationFrame(e)}(),n(),()=>{var t;u.forEach((t=>{s&&t.removeEventListener("scroll",n),r&&t.removeEventListener("resize",n)})),null==(t=d)||t.disconnect(),d=null,c&&cancelAnimationFrame(a)}},t.computePosition=(t,n,o)=>{const i=new Map,r={platform:A,...o},l={...r.platform,_c:i};return e.computePosition(t,n,{...r,platform:l})},t.getOverflowAncestors=S,t.platform=A,Object.defineProperty(t,"__esModule",{value:!0})})); \ No newline at end of file diff --git a/src-tauri/src/assets/html2canvas.js b/src-tauri/src/vendors/html2canvas.js similarity index 100% rename from src-tauri/src/assets/html2canvas.js rename to src-tauri/src/vendors/html2canvas.js diff --git a/src-tauri/src/assets/jspdf.js b/src-tauri/src/vendors/jspdf.js similarity index 100% rename from src-tauri/src/assets/jspdf.js rename to src-tauri/src/vendors/jspdf.js diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 406486b..803da8d 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ }, "package": { "productName": "ChatGPT", - "version": "0.7.4" + "version": "0.8.1" }, "tauri": { "allowlist": { @@ -75,4 +75,4 @@ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEIxMjY4OUI5MTVFNjBEMDUKUldRRkRlWVZ1WWttc1NGWEE0RFNSb0RqdnhsekRJZTkwK2hVLzhBZTZnaHExSEZ1ZEdzWkpXTHkK" } } -} +} \ No newline at end of file diff --git a/src/hooks/useChatModel.ts b/src/hooks/useChatModel.ts index 45a816a..980fe1c 100644 --- a/src/hooks/useChatModel.ts +++ b/src/hooks/useChatModel.ts @@ -47,6 +47,7 @@ export function useCacheModel(file = '') { const list = await invoke('cmd_list'); await writeJSON(CHAT_MODEL_CMD_JSON, { name: 'ChatGPT CMD', last_updated: Date.now(), data: list }); await invoke('window_reload', { label: 'core' }); + await invoke('window_reload', { label: 'tray' }); }; return { modelCacheJson, modelCacheSet, modelCacheCmd }; diff --git a/src/layout/index.tsx b/src/layout/index.tsx index 2def6af..bbc7dc9 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -26,7 +26,7 @@ export default function ChatLayout() { }) const checkAppUpdate = async () => { - await invoke('run_check_update', { silent: false }); + await invoke('run_check_update', { silent: false, hasMsg: true }); } return ( diff --git a/src/view/General.tsx b/src/view/General.tsx index ce4416e..6dfbdab 100644 --- a/src/view/General.tsx +++ b/src/view/General.tsx @@ -14,12 +14,12 @@ const AutoUpdateLabel = () => { return ( Auto Update -
Auto Update Policy
- Prompt: prompt to install
- Silent: install silently
- {/*Disable: disable auto update
*/} - +
+
Auto Update Policy
+ Prompt: prompt to install
+ Silent: install silently
+ {/*Disable: disable auto update
*/} +
)}>
) @@ -33,7 +33,22 @@ const OriginLabel = ({ url }: { url: string }) => { ) } -const GlobalShortcut = () => { +const PopupSearchLabel = () => { + return ( + + Pop-up Search + {' '} + +
Generate images according to the content: Select the ChatGPT content with the mouse, no more than 400 characters. the DALL·E 2 button appears, and click to jump (Note: because the search content filled by the script cannot trigger the event directly, you need to enter a space in the input box to make the button clickable).
+
The application is built using Tauri, and due to its security restrictions, some of the action buttons will not work, so we recommend going to your browser.
+ + )}>
+
+ ) +} + +const GlobalShortcutLabel = () => { return (
Global Shortcut @@ -122,6 +137,9 @@ export default function General() { )} + } name="popup_search" valuePropName="checked"> + + Light @@ -138,7 +156,7 @@ export default function General() { {/*Disable*/} - } name="global_shortcut"> + } name="global_shortcut"> } name="origin"> @@ -153,11 +171,8 @@ export default function General() { - - - Reset to defaults + +