From 344db99d357c2e21744fbcded3475bb112a7238c Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 16 Nov 2024 21:16:56 +1000 Subject: [PATCH 001/180] feat: updater includes Qopy in the title --- package.json | 6 +++--- src-tauri/src/api/updater.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2ace70a..172bbb1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "postinstall": "nuxt prepare" }, "dependencies": { - "@tauri-apps/api": "2.1.1", + "@tauri-apps/api": "2.0.3", "@tauri-apps/cli": "2.1.0", "@tauri-apps/plugin-autostart": "2.0.0", "@tauri-apps/plugin-fs": "2.0.2", @@ -21,6 +21,6 @@ "overlayscrollbars": "2.10.0", "overlayscrollbars-vue": "0.5.9", "sass": "1.81.0", - "vue": "3.5.12" + "vue": "3.5.13" } -} +} \ No newline at end of file diff --git a/src-tauri/src/api/updater.rs b/src-tauri/src/api/updater.rs index b8ef00e..b5d1b3c 100644 --- a/src-tauri/src/api/updater.rs +++ b/src-tauri/src/api/updater.rs @@ -20,7 +20,7 @@ pub async fn check_for_updates(app: AppHandle) { app.dialog() .message(msg) - .title("Update Available") + .title("Qopy Update Available") .buttons(MessageDialogButtons::OkCancelCustom(String::from("Install"), String::from("Cancel"))) .show(move |response| { if !response { @@ -31,7 +31,7 @@ pub async fn check_for_updates(app: AppHandle) { Ok(_) => { app.dialog() .message("Update installed successfully. The application needs to restart to apply the changes.") - .title("Update Installed") + .title("Qopy Update Installed") .buttons(MessageDialogButtons::OkCancelCustom(String::from("Restart"), String::from("Cancel"))) .show(move |response| { if response { From 2666132a7e12cd2269fdc3f59a5fffd324995455 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 16 Nov 2024 21:24:24 +1000 Subject: [PATCH 002/180] feat: download for apple --- README.md | 14 ++++++++++++-- public/apple.png | Bin 0 -> 260 bytes 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 public/apple.png diff --git a/README.md b/README.md index 9b0067e..830a7bb 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,22 @@ The fixed and simple clipboard manager for both Windows and Linux. Download for - + Windows - + + macOS (Silicon) + + + + + macOS (Intel) + + + + Linux diff --git a/public/apple.png b/public/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..f9bd6d9f183866dc178a8e1539d42694b7a50850 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa&H|6fVg?3oVGw3ym^DWND9BhG zrk7sR?U?u%lN(b_N2BI@=tcMs(H9mX#W$DyZ|?& z+dQ9jBz@a1cKAL>>hj|LZgEMxVnOWrz<&|f8KpgB=IBem?f^QH!PC{xWt~$(697K$ BR{8({ literal 0 HcmV?d00001 From bfa9cf50185da4ee251fe89fea0fc17a0b5faf10 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:31:37 +1000 Subject: [PATCH 003/180] docs(readme): updated roadmap --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 830a7bb..6f7698f 100644 --- a/README.md +++ b/README.md @@ -59,16 +59,15 @@ The fixed and simple clipboard manager for both Windows and Linux. Qopy is a fixed clipboard manager designed as a simple alternative to the standard clipboard on Windows. It aims to provide a faster, more reliable experience while providing an extensive set of features compared to its Windows counterpart. -🍎 macOS is currently not supported due to a library that is not compatible. - ## 🚧 Roadmap - [ ] [Setup guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md) - [ ] Settings https://github.com/0PandaDEV/Qopy/issues/2 -- [ ] Option for custom keybind https://github.com/0PandaDEV/Qopy/issues/3 - [ ] Metadata for copied items https://github.com/0PandaDEV/Qopy/issues/5 - [ ] Code highlighting https://github.com/0PandaDEV/Qopy/issues/7 - [ ] Streamshare integration https://github.com/0PandaDEV/Qopy/issues/4 - [ ] Cross-device clipboard sharing https://github.com/0PandaDEV/Qopy/issues/8 +- [x] Option for custom keybind https://github.com/0PandaDEV/Qopy/issues/3 +- [x] macOS Support https://github.com/0PandaDEV/Qopy/issues/13 If you have ideas for features to include, please write a feature request [here](https://github.com/0pandadev/Qopy/issues). From fa02076b75db5ef82aceecc84d0515d0b0173429 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:15:07 +1000 Subject: [PATCH 004/180] fix: font incorrect in content view --- assets/css/index.scss | 199 +++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 99 deletions(-) diff --git a/assets/css/index.scss b/assets/css/index.scss index 3390c53..43e9ca7 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -1,10 +1,10 @@ -$primary: #2E2D2B; -$accent: #FEB453; +$primary: #2e2d2b; +$accent: #feb453; $divider: #ffffff0d; -$text: #E5DFD5; -$text2: #ADA9A1; -$mutedtext: #78756F; +$text: #e5dfd5; +$text2: #ada9a1; +$mutedtext: #78756f; .bg { width: 750px; @@ -100,7 +100,7 @@ $mutedtext: #78756F; left: 284px; padding: 8px; height: calc(100vh - 96px); - font-family: CommitMono !important; + font-family: CommitMono Nerd Font !important; font-size: 14px; letter-spacing: 1; border-radius: 10px; @@ -108,9 +108,8 @@ $mutedtext: #78756F; white-space: pre-wrap; word-wrap: break-word; - div { - border-radius: 10px; - font-family: CommitMono !important; + span { + font-family: CommitMono Nerd Font !important; } .full-image { @@ -183,7 +182,7 @@ $mutedtext: #78756F; background-color: $divider; margin-left: 8px; margin-right: 4px; - transition: all .2s; + transition: all 0.2s; } .paste, @@ -195,7 +194,7 @@ $mutedtext: #78756F; gap: 8px; border-radius: 7px; background-color: transparent; - transition: all .2s; + transition: all 0.2s; cursor: pointer; } @@ -204,97 +203,99 @@ $mutedtext: #78756F; background-color: $divider; } - &:hover .paste:hover~.divider, - &:hover .actions:hover~.divider { + &:hover .paste:hover ~ .divider, + &:hover .actions:hover ~ .divider { opacity: 0; } } } .clothoid-corner { - clip-path: polygon(13.890123px 0px, - calc(100% - 13.890123px) 0px, - calc(100% - 12.723414px) 0.004211px, - calc(100% - 11.556933px) 0.025635px, - calc(100% - 10.391895px) 0.085062px, - calc(100% - 9.231074px) 0.199291px, - calc(100% - 8.079275px) 0.382298px, - calc(100% - 6.947448px) 0.662609px, - calc(100% - 5.844179px) 1.039291px, - calc(100% - 4.793324px) 1.542842px, - calc(100% - 3.811369px) 2.169728px, - calc(100% - 2.926417px) 2.926417px, - calc(100% - 2.169728px) 3.811369px, - calc(100% - 1.542842px) 4.793324px, - calc(100% - 1.039291px) 5.844179px, - calc(100% - 0.662609px) 6.947448px, - calc(100% - 0.382298px) 8.079275px, - calc(100% - 0.199291px) 9.231074px, - calc(100% - 0.085062px) 10.391895px, - calc(100% - 0.025635px) 11.556933px, - calc(100% - 0.004211px) 12.723414px, - 100% 13.890123px, - 100% calc(100% - 13.890123px), - calc(100% - 0.004211px) calc(100% - 12.723414px), - calc(100% - 0.025635px) calc(100% - 11.556933px), - calc(100% - 0.085062px) calc(100% - 10.391895px), - calc(100% - 0.199291px) calc(100% - 9.231074px), - calc(100% - 0.382298px) calc(100% - 8.079275px), - calc(100% - 0.662609px) calc(100% - 6.947448px), - calc(100% - 1.039291px) calc(100% - 5.844179px), - calc(100% - 1.542842px) calc(100% - 4.793324px), - calc(100% - 2.169728px) calc(100% - 3.811369px), - calc(100% - 2.926417px) calc(100% - 2.926417px), - calc(100% - 3.811369px) calc(100% - 2.169728px), - calc(100% - 4.793324px) calc(100% - 1.542842px), - calc(100% - 5.844179px) calc(100% - 1.039291px), - calc(100% - 6.947448px) calc(100% - 0.662609px), - calc(100% - 8.079275px) calc(100% - 0.382298px), - calc(100% - 9.231074px) calc(100% - 0.199291px), - calc(100% - 10.391895px) calc(100% - 0.085062px), - calc(100% - 11.556933px) calc(100% - 0.025635px), - calc(100% - 12.723414px) calc(100% - 0.004211px), - calc(100% - 13.890123px) 100%, - 13.890123px 100%, - 12.723414px calc(100% - 0.004211px), - 11.556933px calc(100% - 0.025635px), - 10.391895px calc(100% - 0.085062px), - 9.231074px calc(100% - 0.199291px), - 8.079275px calc(100% - 0.382298px), - 6.947448px calc(100% - 0.662609px), - 5.844179px calc(100% - 1.039291px), - 4.793324px calc(100% - 1.542842px), - 3.811369px calc(100% - 2.169728px), - 2.926417px calc(100% - 2.926417px), - 2.169728px calc(100% - 3.811369px), - 1.542842px calc(100% - 4.793324px), - 1.039291px calc(100% - 5.844179px), - 0.662609px calc(100% - 6.947448px), - 0.382298px calc(100% - 8.079275px), - 0.199291px calc(100% - 9.231074px), - 0.085062px calc(100% - 10.391895px), - 0.025635px calc(100% - 11.556933px), - 0.004211px calc(100% - 12.723414px), - 0px calc(100% - 13.890123px), - 0px 13.890123px, - 0.004211px 12.723414px, - 0.025635px 11.556933px, - 0.085062px 10.391895px, - 0.199291px 9.231074px, - 0.382298px 8.079275px, - 0.662609px 6.947448px, - 1.039291px 5.844179px, - 1.542842px 4.793324px, - 2.169728px 3.811369px, - 2.926417px 2.926417px, - 3.811369px 2.169728px, - 4.793324px 1.542842px, - 5.844179px 1.039291px, - 6.947448px 0.662609px, - 8.079275px 0.382298px, - 9.231074px 0.199291px, - 10.391895px 0.085062px, - 11.556933px 0.025635px, - 12.723414px 0.004211px, - 13.890123px 0px); -} \ No newline at end of file + clip-path: polygon( + 13.890123px 0px, + calc(100% - 13.890123px) 0px, + calc(100% - 12.723414px) 0.004211px, + calc(100% - 11.556933px) 0.025635px, + calc(100% - 10.391895px) 0.085062px, + calc(100% - 9.231074px) 0.199291px, + calc(100% - 8.079275px) 0.382298px, + calc(100% - 6.947448px) 0.662609px, + calc(100% - 5.844179px) 1.039291px, + calc(100% - 4.793324px) 1.542842px, + calc(100% - 3.811369px) 2.169728px, + calc(100% - 2.926417px) 2.926417px, + calc(100% - 2.169728px) 3.811369px, + calc(100% - 1.542842px) 4.793324px, + calc(100% - 1.039291px) 5.844179px, + calc(100% - 0.662609px) 6.947448px, + calc(100% - 0.382298px) 8.079275px, + calc(100% - 0.199291px) 9.231074px, + calc(100% - 0.085062px) 10.391895px, + calc(100% - 0.025635px) 11.556933px, + calc(100% - 0.004211px) 12.723414px, + 100% 13.890123px, + 100% calc(100% - 13.890123px), + calc(100% - 0.004211px) calc(100% - 12.723414px), + calc(100% - 0.025635px) calc(100% - 11.556933px), + calc(100% - 0.085062px) calc(100% - 10.391895px), + calc(100% - 0.199291px) calc(100% - 9.231074px), + calc(100% - 0.382298px) calc(100% - 8.079275px), + calc(100% - 0.662609px) calc(100% - 6.947448px), + calc(100% - 1.039291px) calc(100% - 5.844179px), + calc(100% - 1.542842px) calc(100% - 4.793324px), + calc(100% - 2.169728px) calc(100% - 3.811369px), + calc(100% - 2.926417px) calc(100% - 2.926417px), + calc(100% - 3.811369px) calc(100% - 2.169728px), + calc(100% - 4.793324px) calc(100% - 1.542842px), + calc(100% - 5.844179px) calc(100% - 1.039291px), + calc(100% - 6.947448px) calc(100% - 0.662609px), + calc(100% - 8.079275px) calc(100% - 0.382298px), + calc(100% - 9.231074px) calc(100% - 0.199291px), + calc(100% - 10.391895px) calc(100% - 0.085062px), + calc(100% - 11.556933px) calc(100% - 0.025635px), + calc(100% - 12.723414px) calc(100% - 0.004211px), + calc(100% - 13.890123px) 100%, + 13.890123px 100%, + 12.723414px calc(100% - 0.004211px), + 11.556933px calc(100% - 0.025635px), + 10.391895px calc(100% - 0.085062px), + 9.231074px calc(100% - 0.199291px), + 8.079275px calc(100% - 0.382298px), + 6.947448px calc(100% - 0.662609px), + 5.844179px calc(100% - 1.039291px), + 4.793324px calc(100% - 1.542842px), + 3.811369px calc(100% - 2.169728px), + 2.926417px calc(100% - 2.926417px), + 2.169728px calc(100% - 3.811369px), + 1.542842px calc(100% - 4.793324px), + 1.039291px calc(100% - 5.844179px), + 0.662609px calc(100% - 6.947448px), + 0.382298px calc(100% - 8.079275px), + 0.199291px calc(100% - 9.231074px), + 0.085062px calc(100% - 10.391895px), + 0.025635px calc(100% - 11.556933px), + 0.004211px calc(100% - 12.723414px), + 0px calc(100% - 13.890123px), + 0px 13.890123px, + 0.004211px 12.723414px, + 0.025635px 11.556933px, + 0.085062px 10.391895px, + 0.199291px 9.231074px, + 0.382298px 8.079275px, + 0.662609px 6.947448px, + 1.039291px 5.844179px, + 1.542842px 4.793324px, + 2.169728px 3.811369px, + 2.926417px 2.926417px, + 3.811369px 2.169728px, + 4.793324px 1.542842px, + 5.844179px 1.039291px, + 6.947448px 0.662609px, + 8.079275px 0.382298px, + 9.231074px 0.199291px, + 10.391895px 0.085062px, + 11.556933px 0.025635px, + 12.723414px 0.004211px, + 13.890123px 0px + ); +} From 042d708c4bbbdb911cd4d924a9310544353c88b7 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:15:27 +1000 Subject: [PATCH 005/180] fix: not reloading when nothing is new --- pages/index.vue | 289 ++++++++++++++++++++++++++++++------------------ 1 file changed, 179 insertions(+), 110 deletions(-) diff --git a/pages/index.vue b/pages/index.vue index fd456d2..559e557 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -2,24 +2,24 @@
+ spellcheck="false" class="search" type="text" placeholder="Type to filter entries..." />
- +

Qopy

Paste

- +

Actions

- - - + + +
@@ -28,48 +28,52 @@ :options="{ scrollbars: { autoHide: 'scroll' } }">
- Image + Image
YouTube Thumbnail - {{ selectedItem?.content || '' }} + :src="getYoutubeThumbnail(selectedItem.content)" alt="YouTube Thumbnail" class="full-image" /> + {{ selectedItem?.content || "" }}
\ No newline at end of file +@use "~/assets/css/index.scss"; + From 3ae0313975e9e15bac3a7454a1ff8de7b121dc81 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:15:38 +1000 Subject: [PATCH 006/180] fix: pasting not working on mac --- src-tauri/src/api/clipboard.rs | 43 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src-tauri/src/api/clipboard.rs b/src-tauri/src/api/clipboard.rs index c587cb4..3150c58 100644 --- a/src-tauri/src/api/clipboard.rs +++ b/src-tauri/src/api/clipboard.rs @@ -62,7 +62,28 @@ pub async fn write_and_paste( IS_PROGRAMMATIC_PASTE.store(true, Ordering::SeqCst); - simulate_paste(); + thread::spawn(|| { + thread::sleep(Duration::from_millis(100)); + + #[cfg(target_os = "macos")] + let modifier_key = Key::MetaLeft; + #[cfg(not(target_os = "macos"))] + let modifier_key = Key::ControlLeft; + + let events = vec![ + EventType::KeyPress(modifier_key), + EventType::KeyPress(Key::KeyV), + EventType::KeyRelease(Key::KeyV), + EventType::KeyRelease(modifier_key), + ]; + + for event in events { + if let Err(e) = simulate(&event) { + println!("Simulation error: {:?}", e); + } + thread::sleep(Duration::from_millis(20)); + } + }); tokio::spawn(async { tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; @@ -72,22 +93,6 @@ pub async fn write_and_paste( Ok(()) } -fn simulate_paste() { - let mut events = vec![ - EventType::KeyPress(Key::ControlLeft), - EventType::KeyPress(Key::KeyV), - EventType::KeyRelease(Key::KeyV), - EventType::KeyRelease(Key::ControlLeft), - ]; - - thread::sleep(Duration::from_millis(100)); - - for event in events.drain(..) { - simulate(&event).unwrap(); - thread::sleep(Duration::from_millis(20)); - } -} - #[tauri::command] pub fn get_image_path(app_handle: tauri::AppHandle, filename: String) -> String { let app_data_dir = app_handle @@ -246,6 +251,8 @@ async fn insert_content_if_not_exists( .bind(favicon_base64) .execute(&pool) .await; + + let _ = app_handle.emit("clipboard-content-updated", ()); } } @@ -302,4 +309,4 @@ pub fn start_monitor(app_handle: AppHandle) -> Result<(), String> { .emit("plugin:clipboard://clipboard-monitor/status", true) .map_err(|e| e.to_string())?; Ok(()) -} \ No newline at end of file +} From 7e6b2f8b6357280820cc2a5446f132b1a09cee23 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:16:01 +1000 Subject: [PATCH 007/180] style: formatting --- src-tauri/src/main.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index ac84c7b..19c975b 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -35,22 +35,18 @@ fn main() { let main_window = if let Some(window) = app.get_webview_window("main") { window } else { - WebviewWindow::builder( - app.handle(), - "main", - WebviewUrl::App("index.html".into()) - ) - .title("Qopy") - .resizable(false) - .fullscreen(false) - .inner_size(750.0, 474.0) - .focused(true) - .skip_taskbar(true) - .visible(false) - .decorations(false) - .transparent(true) - .always_on_top(false) - .build()? + WebviewWindow::builder(app.handle(), "main", WebviewUrl::App("index.html".into())) + .title("Qopy") + .resizable(false) + .fullscreen(false) + .inner_size(750.0, 474.0) + .focused(true) + .skip_taskbar(true) + .visible(false) + .decorations(false) + .transparent(true) + .always_on_top(false) + .build()? }; let _ = api::database::setup(app); From f2f554074bed8c0564fedd24205927f17c4fc440 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 23 Nov 2024 14:57:42 +1000 Subject: [PATCH 008/180] style: formatting --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 214 +++++ .prettierignore | 39 + .prettierrc | 10 + GET_STARTED.md | 6 +- README.md | 4 +- app.vue | 48 +- assets/css/index.scss | 512 +++++------ assets/css/keybind.scss | 242 +++--- components/Noise.vue | 8 +- nuxt.config.ts | 24 +- package.json | 55 +- pages/index.vue | 961 +++++++++++---------- pages/keybind.vue | 317 +++---- src-tauri/Cargo.lock | 8 +- src-tauri/Cargo.toml | 14 +- src-tauri/capabilities/default.json | 64 +- src-tauri/src/main.rs | 12 +- src-tauri/tauri.conf.json | 114 ++- tsconfig.json | 4 +- 22 files changed, 1493 insertions(+), 1171 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b7740ca..a856caa 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,7 @@ name: "\U0001F41E Bug report" description: Create a report to help me improve Qopy labels: [Bug] -assignees: +assignees: - 0PandaDEV body: # @@ -17,7 +17,7 @@ body: description: A clear and concise description of what the bug is. validations: required: true - + - type: textarea id: reproduce attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 7d2e94d..bbb7868 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,7 @@ name: "\U0001F4A1 Feature request" description: Suggest an idea for Qopy labels: [Feature] -assignees: +assignees: - 0PandaDEV body: # diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e975560..50d4341 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,7 +151,7 @@ jobs: - uses: actions/upload-artifact@v4 with: name: updater-files-windows - path: | + path: | src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/*.msi.sig diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2b6f76b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,214 @@ +name: "Release" + +on: + push: + tags: + - "v*" + workflow_dispatch: + +jobs: + prepare: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.get_version.outputs.VERSION }} + steps: + - uses: actions/checkout@v4 + - name: Get version + id: get_version + run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT + + build-macos: + needs: prepare + strategy: + matrix: + include: + - args: "--target aarch64-apple-darwin" + arch: "silicon" + - args: "--target x86_64-apple-darwin" + arch: "intel" + runs-on: macos-latest + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + steps: + - uses: actions/checkout@v4 + - name: Redact Sensitive Information + run: | + function redact_output { + sed -e "s/${{ secrets.REDACT_PATTERN }}/REDACTED/g" + } + exec > >(redact_output) 2>&1 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-apple-darwin,x86_64-apple-darwin + - uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri -> target" + cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" + shared-key: "macos-rust-cache" + save-if: "true" + - uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + - run: npm install -g pnpm && pnpm install + - name: Import Apple Developer Certificate + env: + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 + security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain + security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} + TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} + with: + args: ${{ matrix.args }} + tagName: v${{ needs.prepare.outputs.version }} + releaseName: v${{ needs.prepare.outputs.version }} + releaseBody: "See the assets to download this version and install." + releaseDraft: true + prerelease: false + - name: Rename macOS Artifacts + run: | + mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/*.dmg src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.dmg + mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz + mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz.sig src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz.sig + + build-windows: + needs: prepare + strategy: + matrix: + include: + - args: "--target x86_64-pc-windows-msvc" + arch: "x64" + - args: "--target aarch64-pc-windows-msvc" + arch: "arm64" + runs-on: windows-latest + env: + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-pc-windows-msvc,aarch64-pc-windows-msvc + - uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri -> target" + cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" + shared-key: "windows-rust-cache" + save-if: "true" + - uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + - run: npm install -g pnpm && pnpm install + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: ${{ matrix.args }} + tagName: v${{ needs.prepare.outputs.version }} + releaseName: v${{ needs.prepare.outputs.version }} + releaseBody: "See the assets to download this version and install." + releaseDraft: true + prerelease: false + - name: Rename Windows Artifacts + run: | + mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi + mv src-tauri/target/release/bundle/msi/*.msi.sig src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig + + build-linux: + needs: prepare + runs-on: ubuntu-latest + env: + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + - uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri -> target" + cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" + shared-key: "linux-rust-cache" + save-if: "true" + - uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y libwebkit2gtk-4.1-dev build-essential curl wget file libssl-dev libayatana-appindicator3-dev librsvg2-dev libasound2-dev rpm + echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV + - run: npm install -g pnpm && pnpm install + - name: Generate Changelog + id: changelog + run: | + CHANGELOG=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") + echo "CHANGELOG<> $GITHUB_ENV + echo "$CHANGELOG" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: --target x86_64-unknown-linux-gnu + tagName: v${{ needs.prepare.outputs.version }} + releaseName: v${{ needs.prepare.outputs.version }} + releaseBody: | + ## Changelog + ${{ env.CHANGELOG }} + + See the assets to download this version and install. + releaseDraft: true + prerelease: false + - name: Rename Linux Artifacts + run: | + mv src-tauri/target/release/bundle/deb/*.deb src-tauri/target/release/bundle/deb/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb + mv src-tauri/target/release/bundle/appimage/*.AppImage src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage + mv src-tauri/target/release/bundle/appimage/*.AppImage.sig src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage.sig + mv src-tauri/target/release/bundle/rpm/*.rpm src-tauri/target/release/bundle/rpm/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm + - name: Create Draft Release + uses: softprops/action-gh-release@v1 + with: + draft: true + files: | + src-tauri/target/release/bundle/deb/*.deb + src-tauri/target/release/bundle/appimage/*.AppImage + src-tauri/target/release/bundle/appimage/*.AppImage.sig + src-tauri/target/release/bundle/rpm/*.rpm + body: | + ## Changelog + ${{ env.CHANGELOG }} + + See the assets to download this version and install. + tag_name: v${{ needs.prepare.outputs.version }} + name: v${{ needs.prepare.outputs.version }} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..153f712 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,39 @@ +# Rust +/target/ +/src-tauri/target/ +Cargo.lock +*.rs + +# Node +node_modules/ +.nuxt/ +.output/ +dist/ + +# Build +/build/ +/out/ + +# Tauri +.tauri/ + +# System +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Local env files +.env +.env.* + +# IDE +.idea/ +.vscode/ +*.suo +*.ntvs* +*.njsproj +*.sln \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..1289a01 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "useTabs": true, + "printWidth": 100, + "trailingComma": "es5", + "vueIndentScriptAndStyle": true, + "plugins": ["prettier-plugin-vue"] +} \ No newline at end of file diff --git a/GET_STARTED.md b/GET_STARTED.md index 3807b7f..5c1122c 100644 --- a/GET_STARTED.md +++ b/GET_STARTED.md @@ -1,13 +1,13 @@ # Get Started -The hotkey for Qopy is Windows+V which is also the hotkey for the default clipboard manager to turn that off follow [this guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md#disable-windowsv-for-default-clipboard-manager). +The hotkey for Qopy is Windows+V which is also the hotkey for the default clipboard manager to turn that off follow [this guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md#disable-windowsv-for-default-clipboard-manager). All the data of Qopy is stored inside of a SQLite database. The location for the file differs for windows and linux. | Operating System | Path | -|------------------|-------------------------------------------------------| +| ---------------- | ----------------------------------------------------- | | Windows | `C:\Users\USERNAME\AppData\Roaming\net.pandadev.qopy` | -| Linux | `` | +| Linux | `` | ## Disable Windows+V for default clipboard manager diff --git a/README.md b/README.md index 6f7698f..77280a3 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ The fixed and simple clipboard manager for both Windows and Linux. Qopy is a fixed clipboard manager designed as a simple alternative to the standard clipboard on Windows. It aims to provide a faster, more reliable experience while providing an extensive set of features compared to its Windows counterpart. ## 🚧 Roadmap + - [ ] [Setup guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md) - [ ] Settings https://github.com/0PandaDEV/Qopy/issues/2 - [ ] Metadata for copied items https://github.com/0PandaDEV/Qopy/issues/5 @@ -72,6 +73,7 @@ Qopy is a fixed clipboard manager designed as a simple alternative to the standa If you have ideas for features to include, please write a feature request [here](https://github.com/0pandadev/Qopy/issues). ## 📦 Preview + @@ -111,7 +113,7 @@ pnpm build > \[!NOTE] > > Don't worry, it will fail at the end because it can not detect a Private key, but the installer files will be generated regardless of that. -> +> > You can find them in `src-tauri/target/release/bundle`. ## 📝 License diff --git a/app.vue b/app.vue index a54b0c0..1adba95 100644 --- a/app.vue +++ b/app.vue @@ -1,31 +1,31 @@ \ No newline at end of file + diff --git a/assets/css/index.scss b/assets/css/index.scss index 43e9ca7..8a0d3a1 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -7,295 +7,295 @@ $text2: #ada9a1; $mutedtext: #78756f; .bg { - width: 750px; - height: 474px; - background-color: $primary; - border: 1px solid $divider; - border-radius: 12px; - z-index: -1; - position: fixed; - outline: none; + width: 750px; + height: 474px; + background-color: $primary; + border: 1px solid $divider; + border-radius: 12px; + z-index: -1; + position: fixed; + outline: none; } .search { - width: 100%; - position: fixed; - top: 0; - left: 0; - height: 54px; - background-color: transparent; - outline: none; - border: none; - font-size: 18px; - color: $mutedtext; - padding-inline: 16px; - border-bottom: 1px solid $divider; - font-family: SFRoundedMedium; + width: 100%; + position: fixed; + top: 0; + left: 0; + height: 54px; + background-color: transparent; + outline: none; + border: none; + font-size: 18px; + color: $mutedtext; + padding-inline: 16px; + border-bottom: 1px solid $divider; + font-family: SFRoundedMedium; } .results { - position: absolute; - width: 284px; - top: 53px; - left: 0; - height: calc(100vh - 95px); - border-right: 1px solid $divider; - display: flex; - flex-direction: column; - padding-inline: 8px; - padding-bottom: 8px; - overflow-y: auto; - overflow-x: hidden; + position: absolute; + width: 284px; + top: 53px; + left: 0; + height: calc(100vh - 95px); + border-right: 1px solid $divider; + display: flex; + flex-direction: column; + padding-inline: 8px; + padding-bottom: 8px; + overflow-y: auto; + overflow-x: hidden; - .result { - height: 40px; - font-size: 14px; - align-items: center; - display: flex; - padding: 10px; - padding-inline: 10px; - letter-spacing: 0.5px; - gap: 10px; - overflow: hidden; - text-overflow: clip; - white-space: nowrap; - } + .result { + height: 40px; + font-size: 14px; + align-items: center; + display: flex; + padding: 10px; + padding-inline: 10px; + letter-spacing: 0.5px; + gap: 10px; + overflow: hidden; + text-overflow: clip; + white-space: nowrap; + } - .result { - cursor: pointer; + .result { + cursor: pointer; - &.selected { - background-color: $divider; - } - } + &.selected { + background-color: $divider; + } + } - .time-separator { - font-size: 12px; - color: $text2; - font-family: SFRoundedSemiBold; - padding-left: 8px; - padding-bottom: 8px; - padding-top: 14px; - } + .time-separator { + font-size: 12px; + color: $text2; + font-family: SFRoundedSemiBold; + padding-left: 8px; + padding-bottom: 8px; + padding-top: 14px; + } - .favicon { - width: 18px; - height: 18px; - } + .favicon { + width: 18px; + height: 18px; + } - .image { - width: 18px; - height: 18px; - } + .image { + width: 18px; + height: 18px; + } - .icon { - width: 20px; - height: 18px; - } + .icon { + width: 20px; + height: 18px; + } } .content { - position: absolute; - top: 53px; - left: 284px; - padding: 8px; - height: calc(100vh - 96px); - font-family: CommitMono Nerd Font !important; - font-size: 14px; - letter-spacing: 1; - border-radius: 10px; - width: calc(100vw - 286px); - white-space: pre-wrap; - word-wrap: break-word; + position: absolute; + top: 53px; + left: 284px; + padding: 8px; + height: calc(100vh - 96px); + font-family: CommitMono Nerd Font !important; + font-size: 14px; + letter-spacing: 1; + border-radius: 10px; + width: calc(100vw - 286px); + white-space: pre-wrap; + word-wrap: break-word; - span { - font-family: CommitMono Nerd Font !important; - } + span { + font-family: CommitMono Nerd Font !important; + } - .full-image { - width: 100%; - aspect-ratio: 16 / 9; - object-fit: cover; - object-position: center; - } + .full-image { + width: 100%; + aspect-ratio: 16 / 9; + object-fit: cover; + object-position: center; + } - .image { - max-width: 100%; - max-height: 100%; - object-fit: contain; - object-position: top left; - } + .image { + max-width: 100%; + max-height: 100%; + object-fit: contain; + object-position: top left; + } } .bottom-bar { - height: 40px; - width: calc(100vw - 2px); - backdrop-filter: blur(18px); - background-color: hsla(40, 3%, 16%, 0.8); - position: fixed; - bottom: 1px; - left: 1px; - z-index: 100; - border-radius: 0 0 12px 12px; - display: flex; - flex-direction: row; - justify-content: space-between; - padding-inline: 12px; - padding-right: 6px; - padding-top: 1px; - align-items: center; - font-size: 14px; - border-top: 1px solid $divider; + height: 40px; + width: calc(100vw - 2px); + backdrop-filter: blur(18px); + background-color: hsla(40, 3%, 16%, 0.8); + position: fixed; + bottom: 1px; + left: 1px; + z-index: 100; + border-radius: 0 0 12px 12px; + display: flex; + flex-direction: row; + justify-content: space-between; + padding-inline: 12px; + padding-right: 6px; + padding-top: 1px; + align-items: center; + font-size: 14px; + border-top: 1px solid $divider; - p { - color: $text2; - } + p { + color: $text2; + } - .left { - display: flex; - align-items: center; - gap: 8px; + .left { + display: flex; + align-items: center; + gap: 8px; - .logo { - width: 18px; - height: 18px; - } - } + .logo { + width: 18px; + height: 18px; + } + } - .right { - display: flex; - align-items: center; + .right { + display: flex; + align-items: center; - .paste p { - color: $text; - } + .paste p { + color: $text; + } - .actions div { - display: flex; - align-items: center; - gap: 2px; - } + .actions div { + display: flex; + align-items: center; + gap: 2px; + } - .divider { - width: 2px; - height: 12px; - background-color: $divider; - margin-left: 8px; - margin-right: 4px; - transition: all 0.2s; - } + .divider { + width: 2px; + height: 12px; + background-color: $divider; + margin-left: 8px; + margin-right: 4px; + transition: all 0.2s; + } - .paste, - .actions { - padding: 4px; - padding-left: 8px; - display: flex; - align-items: center; - gap: 8px; - border-radius: 7px; - background-color: transparent; - transition: all 0.2s; - cursor: pointer; - } + .paste, + .actions { + padding: 4px; + padding-left: 8px; + display: flex; + align-items: center; + gap: 8px; + border-radius: 7px; + background-color: transparent; + transition: all 0.2s; + cursor: pointer; + } - .paste:hover, - .actions:hover { - background-color: $divider; - } + .paste:hover, + .actions:hover { + background-color: $divider; + } - &:hover .paste:hover ~ .divider, - &:hover .actions:hover ~ .divider { - opacity: 0; - } - } + &:hover .paste:hover ~ .divider, + &:hover .actions:hover ~ .divider { + opacity: 0; + } + } } .clothoid-corner { - clip-path: polygon( - 13.890123px 0px, - calc(100% - 13.890123px) 0px, - calc(100% - 12.723414px) 0.004211px, - calc(100% - 11.556933px) 0.025635px, - calc(100% - 10.391895px) 0.085062px, - calc(100% - 9.231074px) 0.199291px, - calc(100% - 8.079275px) 0.382298px, - calc(100% - 6.947448px) 0.662609px, - calc(100% - 5.844179px) 1.039291px, - calc(100% - 4.793324px) 1.542842px, - calc(100% - 3.811369px) 2.169728px, - calc(100% - 2.926417px) 2.926417px, - calc(100% - 2.169728px) 3.811369px, - calc(100% - 1.542842px) 4.793324px, - calc(100% - 1.039291px) 5.844179px, - calc(100% - 0.662609px) 6.947448px, - calc(100% - 0.382298px) 8.079275px, - calc(100% - 0.199291px) 9.231074px, - calc(100% - 0.085062px) 10.391895px, - calc(100% - 0.025635px) 11.556933px, - calc(100% - 0.004211px) 12.723414px, - 100% 13.890123px, - 100% calc(100% - 13.890123px), - calc(100% - 0.004211px) calc(100% - 12.723414px), - calc(100% - 0.025635px) calc(100% - 11.556933px), - calc(100% - 0.085062px) calc(100% - 10.391895px), - calc(100% - 0.199291px) calc(100% - 9.231074px), - calc(100% - 0.382298px) calc(100% - 8.079275px), - calc(100% - 0.662609px) calc(100% - 6.947448px), - calc(100% - 1.039291px) calc(100% - 5.844179px), - calc(100% - 1.542842px) calc(100% - 4.793324px), - calc(100% - 2.169728px) calc(100% - 3.811369px), - calc(100% - 2.926417px) calc(100% - 2.926417px), - calc(100% - 3.811369px) calc(100% - 2.169728px), - calc(100% - 4.793324px) calc(100% - 1.542842px), - calc(100% - 5.844179px) calc(100% - 1.039291px), - calc(100% - 6.947448px) calc(100% - 0.662609px), - calc(100% - 8.079275px) calc(100% - 0.382298px), - calc(100% - 9.231074px) calc(100% - 0.199291px), - calc(100% - 10.391895px) calc(100% - 0.085062px), - calc(100% - 11.556933px) calc(100% - 0.025635px), - calc(100% - 12.723414px) calc(100% - 0.004211px), - calc(100% - 13.890123px) 100%, - 13.890123px 100%, - 12.723414px calc(100% - 0.004211px), - 11.556933px calc(100% - 0.025635px), - 10.391895px calc(100% - 0.085062px), - 9.231074px calc(100% - 0.199291px), - 8.079275px calc(100% - 0.382298px), - 6.947448px calc(100% - 0.662609px), - 5.844179px calc(100% - 1.039291px), - 4.793324px calc(100% - 1.542842px), - 3.811369px calc(100% - 2.169728px), - 2.926417px calc(100% - 2.926417px), - 2.169728px calc(100% - 3.811369px), - 1.542842px calc(100% - 4.793324px), - 1.039291px calc(100% - 5.844179px), - 0.662609px calc(100% - 6.947448px), - 0.382298px calc(100% - 8.079275px), - 0.199291px calc(100% - 9.231074px), - 0.085062px calc(100% - 10.391895px), - 0.025635px calc(100% - 11.556933px), - 0.004211px calc(100% - 12.723414px), - 0px calc(100% - 13.890123px), - 0px 13.890123px, - 0.004211px 12.723414px, - 0.025635px 11.556933px, - 0.085062px 10.391895px, - 0.199291px 9.231074px, - 0.382298px 8.079275px, - 0.662609px 6.947448px, - 1.039291px 5.844179px, - 1.542842px 4.793324px, - 2.169728px 3.811369px, - 2.926417px 2.926417px, - 3.811369px 2.169728px, - 4.793324px 1.542842px, - 5.844179px 1.039291px, - 6.947448px 0.662609px, - 8.079275px 0.382298px, - 9.231074px 0.199291px, - 10.391895px 0.085062px, - 11.556933px 0.025635px, - 12.723414px 0.004211px, - 13.890123px 0px - ); + clip-path: polygon( + 13.890123px 0px, + calc(100% - 13.890123px) 0px, + calc(100% - 12.723414px) 0.004211px, + calc(100% - 11.556933px) 0.025635px, + calc(100% - 10.391895px) 0.085062px, + calc(100% - 9.231074px) 0.199291px, + calc(100% - 8.079275px) 0.382298px, + calc(100% - 6.947448px) 0.662609px, + calc(100% - 5.844179px) 1.039291px, + calc(100% - 4.793324px) 1.542842px, + calc(100% - 3.811369px) 2.169728px, + calc(100% - 2.926417px) 2.926417px, + calc(100% - 2.169728px) 3.811369px, + calc(100% - 1.542842px) 4.793324px, + calc(100% - 1.039291px) 5.844179px, + calc(100% - 0.662609px) 6.947448px, + calc(100% - 0.382298px) 8.079275px, + calc(100% - 0.199291px) 9.231074px, + calc(100% - 0.085062px) 10.391895px, + calc(100% - 0.025635px) 11.556933px, + calc(100% - 0.004211px) 12.723414px, + 100% 13.890123px, + 100% calc(100% - 13.890123px), + calc(100% - 0.004211px) calc(100% - 12.723414px), + calc(100% - 0.025635px) calc(100% - 11.556933px), + calc(100% - 0.085062px) calc(100% - 10.391895px), + calc(100% - 0.199291px) calc(100% - 9.231074px), + calc(100% - 0.382298px) calc(100% - 8.079275px), + calc(100% - 0.662609px) calc(100% - 6.947448px), + calc(100% - 1.039291px) calc(100% - 5.844179px), + calc(100% - 1.542842px) calc(100% - 4.793324px), + calc(100% - 2.169728px) calc(100% - 3.811369px), + calc(100% - 2.926417px) calc(100% - 2.926417px), + calc(100% - 3.811369px) calc(100% - 2.169728px), + calc(100% - 4.793324px) calc(100% - 1.542842px), + calc(100% - 5.844179px) calc(100% - 1.039291px), + calc(100% - 6.947448px) calc(100% - 0.662609px), + calc(100% - 8.079275px) calc(100% - 0.382298px), + calc(100% - 9.231074px) calc(100% - 0.199291px), + calc(100% - 10.391895px) calc(100% - 0.085062px), + calc(100% - 11.556933px) calc(100% - 0.025635px), + calc(100% - 12.723414px) calc(100% - 0.004211px), + calc(100% - 13.890123px) 100%, + 13.890123px 100%, + 12.723414px calc(100% - 0.004211px), + 11.556933px calc(100% - 0.025635px), + 10.391895px calc(100% - 0.085062px), + 9.231074px calc(100% - 0.199291px), + 8.079275px calc(100% - 0.382298px), + 6.947448px calc(100% - 0.662609px), + 5.844179px calc(100% - 1.039291px), + 4.793324px calc(100% - 1.542842px), + 3.811369px calc(100% - 2.169728px), + 2.926417px calc(100% - 2.926417px), + 2.169728px calc(100% - 3.811369px), + 1.542842px calc(100% - 4.793324px), + 1.039291px calc(100% - 5.844179px), + 0.662609px calc(100% - 6.947448px), + 0.382298px calc(100% - 8.079275px), + 0.199291px calc(100% - 9.231074px), + 0.085062px calc(100% - 10.391895px), + 0.025635px calc(100% - 11.556933px), + 0.004211px calc(100% - 12.723414px), + 0px calc(100% - 13.890123px), + 0px 13.890123px, + 0.004211px 12.723414px, + 0.025635px 11.556933px, + 0.085062px 10.391895px, + 0.199291px 9.231074px, + 0.382298px 8.079275px, + 0.662609px 6.947448px, + 1.039291px 5.844179px, + 1.542842px 4.793324px, + 2.169728px 3.811369px, + 2.926417px 2.926417px, + 3.811369px 2.169728px, + 4.793324px 1.542842px, + 5.844179px 1.039291px, + 6.947448px 0.662609px, + 8.079275px 0.382298px, + 9.231074px 0.199291px, + 10.391895px 0.085062px, + 11.556933px 0.025635px, + 12.723414px 0.004211px, + 13.890123px 0px + ); } diff --git a/assets/css/keybind.scss b/assets/css/keybind.scss index c3ad9d4..9793148 100644 --- a/assets/css/keybind.scss +++ b/assets/css/keybind.scss @@ -1,149 +1,149 @@ -$primary: #2E2D2B; -$accent: #FEB453; +$primary: #2e2d2b; +$accent: #feb453; $divider: #ffffff0d; -$text: #E5DFD5; -$text2: #ADA9A1; -$mutedtext: #78756F; +$text: #e5dfd5; +$text2: #ada9a1; +$mutedtext: #78756f; .bg { - width: 750px; - height: 474px; - background-color: $primary; - border: 1px solid $divider; - border-radius: 12px; - z-index: -1; - position: fixed; - outline: none; + width: 750px; + height: 474px; + background-color: $primary; + border: 1px solid $divider; + border-radius: 12px; + z-index: -1; + position: fixed; + outline: none; } .back { - position: absolute; - top: 16px; - left: 16px; - display: flex; - gap: 8px; - align-items: center; + position: absolute; + top: 16px; + left: 16px; + display: flex; + gap: 8px; + align-items: center; - img{ - background-color: $divider; - border-radius: 6px; - padding: 8px 6px; - } + img { + background-color: $divider; + border-radius: 6px; + padding: 8px 6px; + } - p { - color: $text2; - } + p { + color: $text2; + } } .keybind-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; - gap: 6px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + gap: 6px; - .title { - font-size: 20px; - font-weight: 800; - } + .title { + font-size: 20px; + font-weight: 800; + } - .keybind-input { - padding: 6px; - border: 1px solid $divider; - color: $text2; - display: flex; - border-radius: 13px; - outline: none; - gap: 6px; + .keybind-input { + padding: 6px; + border: 1px solid $divider; + color: $text2; + display: flex; + border-radius: 13px; + outline: none; + gap: 6px; - .key { - color: $text2; - font-family: SFRoundedMedium; - background-color: $divider; - padding: 6px 8px; - border-radius: 8px; - } - } + .key { + color: $text2; + font-family: SFRoundedMedium; + background-color: $divider; + padding: 6px 8px; + border-radius: 8px; + } + } - .keybind-input:focus { - border: 1px solid rgba(255, 255, 255, 0.2); - } + .keybind-input:focus { + border: 1px solid rgba(255, 255, 255, 0.2); + } } .bottom-bar { - height: 40px; - width: calc(100vw - 2px); - backdrop-filter: blur(18px); - background-color: hsla(40, 3%, 16%, 0.8); - position: fixed; - bottom: 1px; - left: 1px; - z-index: 100; - border-radius: 0 0 12px 12px; - display: flex; - flex-direction: row; - justify-content: space-between; - padding-inline: 12px; - padding-right: 6px; - padding-top: 1px; - align-items: center; - font-size: 14px; - border-top: 1px solid $divider; + height: 40px; + width: calc(100vw - 2px); + backdrop-filter: blur(18px); + background-color: hsla(40, 3%, 16%, 0.8); + position: fixed; + bottom: 1px; + left: 1px; + z-index: 100; + border-radius: 0 0 12px 12px; + display: flex; + flex-direction: row; + justify-content: space-between; + padding-inline: 12px; + padding-right: 6px; + padding-top: 1px; + align-items: center; + font-size: 14px; + border-top: 1px solid $divider; - p { - color: $text2; - } + p { + color: $text2; + } - .left { - display: flex; - align-items: center; - gap: 8px; + .left { + display: flex; + align-items: center; + gap: 8px; - .logo { - width: 18px; - height: 18px; - } - } + .logo { + width: 18px; + height: 18px; + } + } - .right { - display: flex; - align-items: center; + .right { + display: flex; + align-items: center; - .actions div { - display: flex; - align-items: center; - gap: 2px; - } + .actions div { + display: flex; + align-items: center; + gap: 2px; + } - .divider { - width: 2px; - height: 12px; - background-color: $divider; - margin-left: 8px; - margin-right: 4px; - transition: all .2s; - } + .divider { + width: 2px; + height: 12px; + background-color: $divider; + margin-left: 8px; + margin-right: 4px; + transition: all 0.2s; + } - .actions { - padding: 4px; - padding-left: 8px; - display: flex; - align-items: center; - gap: 8px; - border-radius: 7px; - background-color: transparent; - transition: all .2s; - cursor: pointer; - } + .actions { + padding: 4px; + padding-left: 8px; + display: flex; + align-items: center; + gap: 8px; + border-radius: 7px; + background-color: transparent; + transition: all 0.2s; + cursor: pointer; + } - .actions:hover { - background-color: $divider; - } + .actions:hover { + background-color: $divider; + } - &:hover .actions:hover~.divider { - opacity: 0; - } - } -} \ No newline at end of file + &:hover .actions:hover ~ .divider { + opacity: 0; + } + } +} diff --git a/components/Noise.vue b/components/Noise.vue index 41bb879..6f99508 100644 --- a/components/Noise.vue +++ b/components/Noise.vue @@ -1,9 +1,9 @@ \ No newline at end of file + diff --git a/nuxt.config.ts b/nuxt.config.ts index 071a2b2..8625c3b 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,15 +1,15 @@ // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ - devtools: { enabled: false }, - compatibilityDate: "2024-07-04", - ssr: false, - vite: { - css: { - preprocessorOptions: { - scss: { - api: "modern-compiler", - }, - }, - }, - }, + devtools: { enabled: false }, + compatibilityDate: "2024-07-04", + ssr: false, + vite: { + css: { + preprocessorOptions: { + scss: { + api: "modern-compiler", + }, + }, + }, + }, }); diff --git a/package.json b/package.json index 172bbb1..912abfe 100644 --- a/package.json +++ b/package.json @@ -1,26 +1,31 @@ { - "name": "nuxt-app", - "private": true, - "type": "module", - "scripts": { - "build": "tauri build", - "dev": "tauri dev", - "generate": "nuxt generate", - "preview": "nuxt preview", - "postinstall": "nuxt prepare" - }, - "dependencies": { - "@tauri-apps/api": "2.0.3", - "@tauri-apps/cli": "2.1.0", - "@tauri-apps/plugin-autostart": "2.0.0", - "@tauri-apps/plugin-fs": "2.0.2", - "@tauri-apps/plugin-os": "2.0.0", - "@tauri-apps/plugin-sql": "2.0.1", - "nuxt": "3.14.159", - "nuxt-build-cache": "0.1.1", - "overlayscrollbars": "2.10.0", - "overlayscrollbars-vue": "0.5.9", - "sass": "1.81.0", - "vue": "3.5.13" - } -} \ No newline at end of file + "name": "nuxt-app", + "dependencies": { + "@tauri-apps/api": "2.1.1", + "@tauri-apps/cli": "2.1.0", + "@tauri-apps/plugin-autostart": "2.0.0", + "@tauri-apps/plugin-fs": "2.0.2", + "@tauri-apps/plugin-os": "2.0.0", + "@tauri-apps/plugin-sql": "2.0.1", + "nuxt": "3.14.1592", + "nuxt-build-cache": "0.1.1", + "overlayscrollbars": "2.10.0", + "overlayscrollbars-vue": "0.5.9", + "prettier": "^3.3.3", + "sass": "1.81.0", + "vue": "3.5.13" + }, + "private": true, + "scripts": { + "build": "tauri build", + "dev": "tauri dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare", + "format": "prettier --write \"**/*.{js,ts,vue,scss,css,json,md}\"" + }, + "type": "module", + "devDependencies": { + "prettier-plugin-vue": "^1.1.6" + } +} diff --git a/pages/index.vue b/pages/index.vue index 559e557..a0d295c 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,533 +1,570 @@ diff --git a/pages/keybind.vue b/pages/keybind.vue index c097a2e..ccc5952 100644 --- a/pages/keybind.vue +++ b/pages/keybind.vue @@ -1,176 +1,185 @@ \ No newline at end of file + @use "~/assets/css/keybind.scss"; + diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 65205ee..a133ffc 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4508,9 +4508,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa 1.0.11", "memchr", @@ -6082,9 +6082,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5f4e589..deb0af7 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.70" tauri-build = { version = "2.0.3", features = [] } [dependencies] -tauri = { version = "2.0.1", features = [ +tauri = { version = "2.1.1", features = [ "macos-private-api", "tray-icon", "image-png", @@ -27,17 +27,17 @@ tauri-plugin-global-shortcut = "2.0.1" sqlx = { version = "0.8.2", features = ["runtime-tokio-native-tls", "sqlite"] } serde = { version = "1.0.215", features = ["derive"] } tokio = { version = "1.41.1", features = ["full"] } -serde_json = "1.0.132" +serde_json = "1.0.133" rdev = "0.5.3" -rand = "0.8" +rand = "0.8.5" base64 = "0.22.1" image = "0.25.5" reqwest = { version = "0.12.9", features = ["blocking"] } -url = "2.5.3" +url = "2.5.4" regex = "1.11.1" -sha2 = "0.10.6" -lazy_static = "1.4.0" -time = "0.3" +sha2 = "0.10.8" +lazy_static = "1.5.0" +time = "0.3.36" global-hotkey = "0.6.3" [features] diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 883a577..cf9ae1a 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -1,34 +1,32 @@ { - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "enables the default permissions", - "windows": [ - "main" - ], - "permissions": [ - "core:path:default", - "core:event:default", - "core:window:default", - "core:webview:default", - "core:app:default", - "core:resources:default", - "core:image:default", - "core:menu:default", - "core:tray:default", - "sql:allow-load", - "sql:allow-select", - "sql:allow-execute", - "autostart:allow-enable", - "autostart:allow-disable", - "autostart:allow-is-enabled", - "os:allow-os-type", - "core:app:allow-app-hide", - "core:app:allow-app-show", - "core:window:allow-hide", - "core:window:allow-show", - "core:window:allow-set-focus", - "core:window:allow-is-focused", - "core:window:allow-is-visible", - "fs:allow-read" - ] -} \ No newline at end of file + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": ["main"], + "permissions": [ + "core:path:default", + "core:event:default", + "core:window:default", + "core:webview:default", + "core:app:default", + "core:resources:default", + "core:image:default", + "core:menu:default", + "core:tray:default", + "sql:allow-load", + "sql:allow-select", + "sql:allow-execute", + "autostart:allow-enable", + "autostart:allow-disable", + "autostart:allow-is-enabled", + "os:allow-os-type", + "core:app:allow-app-hide", + "core:app:allow-app-show", + "core:window:allow-hide", + "core:window:allow-show", + "core:window:allow-set-focus", + "core:window:allow-is-focused", + "core:window:allow-is-visible", + "fs:allow-read" + ] +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 19c975b..68ed873 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -6,6 +6,7 @@ mod api; mod utils; +use tauri::window::{Effect, EffectState, EffectsBuilder}; use tauri::Manager; use tauri::WebviewUrl; use tauri::WebviewWindow; @@ -45,7 +46,9 @@ fn main() { .visible(false) .decorations(false) .transparent(true) - .always_on_top(false) + .always_on_top(true) + .content_protected(true) + .visible_on_all_workspaces(true) .build()? }; @@ -68,6 +71,13 @@ fn main() { api::updater::check_for_updates(app_handle).await; }); + main_window.set_effects( + EffectsBuilder::new() + .effect(Effect::Popover) + .state(EffectState::Active) + .build(), + )?; + Ok(()) }) .on_window_event(|_app, _event| { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index a277188..e05fc4f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,60 +1,58 @@ { - "productName": "Qopy", - "version": "0.2.0", - "identifier": "net.pandadev.qopy", - "build": { - "frontendDist": "../dist", - "devUrl": "http://localhost:3000", - "beforeDevCommand": "pnpm nuxt dev", - "beforeBuildCommand": "pnpm nuxt generate" - }, - "app": { - "windows": [ - { - "title": "Qopy", - "titleBarStyle": "Overlay", - "fullscreen": false, - "resizable": false, - "height": 474, - "width": 750, - "minHeight": 474, - "maxHeight": 474, - "minWidth": 750, - "maxWidth": 750, - "decorations": false, - "center": true, - "shadow": false, - "transparent": true, - "skipTaskbar": true, - "alwaysOnTop": true - } - ], - "security": { - "csp": null - }, - "withGlobalTauri": true, - "macOSPrivateApi": true - }, - "bundle": { - "createUpdaterArtifacts": true, - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "category": "DeveloperTool" - }, - "plugins": { - "updater": { - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDExNDIzNjA1QjE0NjU1OTkKUldTWlZVYXhCVFpDRWNvNmt0UE5lQmZkblEyZGZiZ2tHelJvT2YvNVpLU1RIM1RKZFQrb2tzWWwK", - "endpoints": [ - "https://qopy.pandadev.net/" - ] - } - }, - "$schema": "../node_modules/@tauri-apps/cli/schema.json" + "productName": "Qopy", + "version": "0.2.1", + "identifier": "net.pandadev.qopy", + "build": { + "frontendDist": "../dist", + "devUrl": "http://localhost:3000", + "beforeDevCommand": "pnpm nuxt dev", + "beforeBuildCommand": "pnpm nuxt generate" + }, + "app": { + "windows": [ + { + "title": "Qopy", + "titleBarStyle": "Overlay", + "fullscreen": false, + "resizable": false, + "height": 474, + "width": 750, + "minHeight": 474, + "maxHeight": 474, + "minWidth": 750, + "maxWidth": 750, + "decorations": false, + "center": true, + "shadow": false, + "transparent": true, + "skipTaskbar": true, + "alwaysOnTop": true + } + ], + "security": { + "csp": null + }, + "withGlobalTauri": true, + "macOSPrivateApi": true + }, + "bundle": { + "createUpdaterArtifacts": true, + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "category": "DeveloperTool" + }, + "plugins": { + "updater": { + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDExNDIzNjA1QjE0NjU1OTkKUldTWlZVYXhCVFpDRWNvNmt0UE5lQmZkblEyZGZiZ2tHelJvT2YvNVpLU1RIM1RKZFQrb2tzWWwK", + "endpoints": ["https://qopy.pandadev.net/"] + } + }, + "$schema": "../node_modules/@tauri-apps/cli/schema.json" } diff --git a/tsconfig.json b/tsconfig.json index a746f2a..947f6b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,4 @@ { - // https://nuxt.com/docs/guide/concepts/typescript - "extends": "./.nuxt/tsconfig.json" + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" } From d0b551b3fde6c7012a3be1b8d57599bad6d33a22 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:09:16 +1000 Subject: [PATCH 009/180] Revert "style: formatting" This reverts commit f2f554074bed8c0564fedd24205927f17c4fc440. --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 214 ----- .prettierignore | 39 - .prettierrc | 10 - GET_STARTED.md | 6 +- README.md | 4 +- app.vue | 48 +- assets/css/index.scss | 512 +++++------ assets/css/keybind.scss | 242 +++--- components/Noise.vue | 8 +- nuxt.config.ts | 24 +- package.json | 55 +- pages/index.vue | 961 ++++++++++----------- pages/keybind.vue | 317 ++++--- src-tauri/Cargo.lock | 8 +- src-tauri/Cargo.toml | 14 +- src-tauri/capabilities/default.json | 64 +- src-tauri/src/main.rs | 12 +- src-tauri/tauri.conf.json | 114 +-- tsconfig.json | 4 +- 22 files changed, 1171 insertions(+), 1493 deletions(-) delete mode 100644 .github/workflows/release.yml delete mode 100644 .prettierignore delete mode 100644 .prettierrc diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a856caa..b7740ca 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,7 @@ name: "\U0001F41E Bug report" description: Create a report to help me improve Qopy labels: [Bug] -assignees: +assignees: - 0PandaDEV body: # @@ -17,7 +17,7 @@ body: description: A clear and concise description of what the bug is. validations: required: true - + - type: textarea id: reproduce attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index bbb7868..7d2e94d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,7 @@ name: "\U0001F4A1 Feature request" description: Suggest an idea for Qopy labels: [Feature] -assignees: +assignees: - 0PandaDEV body: # diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50d4341..e975560 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,7 +151,7 @@ jobs: - uses: actions/upload-artifact@v4 with: name: updater-files-windows - path: | + path: | src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/*.msi.sig diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 2b6f76b..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,214 +0,0 @@ -name: "Release" - -on: - push: - tags: - - "v*" - workflow_dispatch: - -jobs: - prepare: - runs-on: ubuntu-latest - outputs: - version: ${{ steps.get_version.outputs.VERSION }} - steps: - - uses: actions/checkout@v4 - - name: Get version - id: get_version - run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT - - build-macos: - needs: prepare - strategy: - matrix: - include: - - args: "--target aarch64-apple-darwin" - arch: "silicon" - - args: "--target x86_64-apple-darwin" - arch: "intel" - runs-on: macos-latest - env: - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - steps: - - uses: actions/checkout@v4 - - name: Redact Sensitive Information - run: | - function redact_output { - sed -e "s/${{ secrets.REDACT_PATTERN }}/REDACTED/g" - } - exec > >(redact_output) 2>&1 - - uses: actions/setup-node@v4 - with: - node-version: 20 - - uses: dtolnay/rust-toolchain@stable - with: - targets: aarch64-apple-darwin,x86_64-apple-darwin - - uses: swatinem/rust-cache@v2 - with: - workspaces: "src-tauri -> target" - cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" - shared-key: "macos-rust-cache" - save-if: "true" - - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm- - - run: npm install -g pnpm && pnpm install - - name: Import Apple Developer Certificate - env: - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - run: | - echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 - security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain - security default-keychain -s build.keychain - security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain - security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain - - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} - TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - with: - args: ${{ matrix.args }} - tagName: v${{ needs.prepare.outputs.version }} - releaseName: v${{ needs.prepare.outputs.version }} - releaseBody: "See the assets to download this version and install." - releaseDraft: true - prerelease: false - - name: Rename macOS Artifacts - run: | - mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/*.dmg src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.dmg - mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz - mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz.sig src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz.sig - - build-windows: - needs: prepare - strategy: - matrix: - include: - - args: "--target x86_64-pc-windows-msvc" - arch: "x64" - - args: "--target aarch64-pc-windows-msvc" - arch: "arm64" - runs-on: windows-latest - env: - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 20 - - uses: dtolnay/rust-toolchain@stable - with: - targets: x86_64-pc-windows-msvc,aarch64-pc-windows-msvc - - uses: swatinem/rust-cache@v2 - with: - workspaces: "src-tauri -> target" - cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" - shared-key: "windows-rust-cache" - save-if: "true" - - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm- - - run: npm install -g pnpm && pnpm install - - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - args: ${{ matrix.args }} - tagName: v${{ needs.prepare.outputs.version }} - releaseName: v${{ needs.prepare.outputs.version }} - releaseBody: "See the assets to download this version and install." - releaseDraft: true - prerelease: false - - name: Rename Windows Artifacts - run: | - mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi - mv src-tauri/target/release/bundle/msi/*.msi.sig src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig - - build-linux: - needs: prepare - runs-on: ubuntu-latest - env: - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: actions/setup-node@v4 - with: - node-version: 20 - - uses: dtolnay/rust-toolchain@stable - - uses: swatinem/rust-cache@v2 - with: - workspaces: "src-tauri -> target" - cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" - shared-key: "linux-rust-cache" - save-if: "true" - - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm- - - name: Install dependencies - run: | - sudo apt update - sudo apt install -y libwebkit2gtk-4.1-dev build-essential curl wget file libssl-dev libayatana-appindicator3-dev librsvg2-dev libasound2-dev rpm - echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV - - run: npm install -g pnpm && pnpm install - - name: Generate Changelog - id: changelog - run: | - CHANGELOG=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") - echo "CHANGELOG<> $GITHUB_ENV - echo "$CHANGELOG" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - args: --target x86_64-unknown-linux-gnu - tagName: v${{ needs.prepare.outputs.version }} - releaseName: v${{ needs.prepare.outputs.version }} - releaseBody: | - ## Changelog - ${{ env.CHANGELOG }} - - See the assets to download this version and install. - releaseDraft: true - prerelease: false - - name: Rename Linux Artifacts - run: | - mv src-tauri/target/release/bundle/deb/*.deb src-tauri/target/release/bundle/deb/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb - mv src-tauri/target/release/bundle/appimage/*.AppImage src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage - mv src-tauri/target/release/bundle/appimage/*.AppImage.sig src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage.sig - mv src-tauri/target/release/bundle/rpm/*.rpm src-tauri/target/release/bundle/rpm/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm - - name: Create Draft Release - uses: softprops/action-gh-release@v1 - with: - draft: true - files: | - src-tauri/target/release/bundle/deb/*.deb - src-tauri/target/release/bundle/appimage/*.AppImage - src-tauri/target/release/bundle/appimage/*.AppImage.sig - src-tauri/target/release/bundle/rpm/*.rpm - body: | - ## Changelog - ${{ env.CHANGELOG }} - - See the assets to download this version and install. - tag_name: v${{ needs.prepare.outputs.version }} - name: v${{ needs.prepare.outputs.version }} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 153f712..0000000 --- a/.prettierignore +++ /dev/null @@ -1,39 +0,0 @@ -# Rust -/target/ -/src-tauri/target/ -Cargo.lock -*.rs - -# Node -node_modules/ -.nuxt/ -.output/ -dist/ - -# Build -/build/ -/out/ - -# Tauri -.tauri/ - -# System -.DS_Store -*.pem - -# Debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Local env files -.env -.env.* - -# IDE -.idea/ -.vscode/ -*.suo -*.ntvs* -*.njsproj -*.sln \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 1289a01..0000000 --- a/.prettierrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "semi": true, - "singleQuote": false, - "tabWidth": 2, - "useTabs": true, - "printWidth": 100, - "trailingComma": "es5", - "vueIndentScriptAndStyle": true, - "plugins": ["prettier-plugin-vue"] -} \ No newline at end of file diff --git a/GET_STARTED.md b/GET_STARTED.md index 5c1122c..3807b7f 100644 --- a/GET_STARTED.md +++ b/GET_STARTED.md @@ -1,13 +1,13 @@ # Get Started -The hotkey for Qopy is Windows+V which is also the hotkey for the default clipboard manager to turn that off follow [this guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md#disable-windowsv-for-default-clipboard-manager). +The hotkey for Qopy is Windows+V which is also the hotkey for the default clipboard manager to turn that off follow [this guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md#disable-windowsv-for-default-clipboard-manager). All the data of Qopy is stored inside of a SQLite database. The location for the file differs for windows and linux. | Operating System | Path | -| ---------------- | ----------------------------------------------------- | +|------------------|-------------------------------------------------------| | Windows | `C:\Users\USERNAME\AppData\Roaming\net.pandadev.qopy` | -| Linux | `` | +| Linux | `` | ## Disable Windows+V for default clipboard manager diff --git a/README.md b/README.md index 77280a3..6f7698f 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,6 @@ The fixed and simple clipboard manager for both Windows and Linux. Qopy is a fixed clipboard manager designed as a simple alternative to the standard clipboard on Windows. It aims to provide a faster, more reliable experience while providing an extensive set of features compared to its Windows counterpart. ## 🚧 Roadmap - - [ ] [Setup guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md) - [ ] Settings https://github.com/0PandaDEV/Qopy/issues/2 - [ ] Metadata for copied items https://github.com/0PandaDEV/Qopy/issues/5 @@ -73,7 +72,6 @@ Qopy is a fixed clipboard manager designed as a simple alternative to the standa If you have ideas for features to include, please write a feature request [here](https://github.com/0pandadev/Qopy/issues). ## 📦 Preview - @@ -113,7 +111,7 @@ pnpm build > \[!NOTE] > > Don't worry, it will fail at the end because it can not detect a Private key, but the installer files will be generated regardless of that. -> +> > You can find them in `src-tauri/target/release/bundle`. ## 📝 License diff --git a/app.vue b/app.vue index 1adba95..a54b0c0 100644 --- a/app.vue +++ b/app.vue @@ -1,31 +1,31 @@ + \ No newline at end of file diff --git a/assets/css/index.scss b/assets/css/index.scss index 8a0d3a1..43e9ca7 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -7,295 +7,295 @@ $text2: #ada9a1; $mutedtext: #78756f; .bg { - width: 750px; - height: 474px; - background-color: $primary; - border: 1px solid $divider; - border-radius: 12px; - z-index: -1; - position: fixed; - outline: none; + width: 750px; + height: 474px; + background-color: $primary; + border: 1px solid $divider; + border-radius: 12px; + z-index: -1; + position: fixed; + outline: none; } .search { - width: 100%; - position: fixed; - top: 0; - left: 0; - height: 54px; - background-color: transparent; - outline: none; - border: none; - font-size: 18px; - color: $mutedtext; - padding-inline: 16px; - border-bottom: 1px solid $divider; - font-family: SFRoundedMedium; + width: 100%; + position: fixed; + top: 0; + left: 0; + height: 54px; + background-color: transparent; + outline: none; + border: none; + font-size: 18px; + color: $mutedtext; + padding-inline: 16px; + border-bottom: 1px solid $divider; + font-family: SFRoundedMedium; } .results { - position: absolute; - width: 284px; - top: 53px; - left: 0; - height: calc(100vh - 95px); - border-right: 1px solid $divider; - display: flex; - flex-direction: column; - padding-inline: 8px; - padding-bottom: 8px; - overflow-y: auto; - overflow-x: hidden; + position: absolute; + width: 284px; + top: 53px; + left: 0; + height: calc(100vh - 95px); + border-right: 1px solid $divider; + display: flex; + flex-direction: column; + padding-inline: 8px; + padding-bottom: 8px; + overflow-y: auto; + overflow-x: hidden; - .result { - height: 40px; - font-size: 14px; - align-items: center; - display: flex; - padding: 10px; - padding-inline: 10px; - letter-spacing: 0.5px; - gap: 10px; - overflow: hidden; - text-overflow: clip; - white-space: nowrap; - } + .result { + height: 40px; + font-size: 14px; + align-items: center; + display: flex; + padding: 10px; + padding-inline: 10px; + letter-spacing: 0.5px; + gap: 10px; + overflow: hidden; + text-overflow: clip; + white-space: nowrap; + } - .result { - cursor: pointer; + .result { + cursor: pointer; - &.selected { - background-color: $divider; - } - } + &.selected { + background-color: $divider; + } + } - .time-separator { - font-size: 12px; - color: $text2; - font-family: SFRoundedSemiBold; - padding-left: 8px; - padding-bottom: 8px; - padding-top: 14px; - } + .time-separator { + font-size: 12px; + color: $text2; + font-family: SFRoundedSemiBold; + padding-left: 8px; + padding-bottom: 8px; + padding-top: 14px; + } - .favicon { - width: 18px; - height: 18px; - } + .favicon { + width: 18px; + height: 18px; + } - .image { - width: 18px; - height: 18px; - } + .image { + width: 18px; + height: 18px; + } - .icon { - width: 20px; - height: 18px; - } + .icon { + width: 20px; + height: 18px; + } } .content { - position: absolute; - top: 53px; - left: 284px; - padding: 8px; - height: calc(100vh - 96px); - font-family: CommitMono Nerd Font !important; - font-size: 14px; - letter-spacing: 1; - border-radius: 10px; - width: calc(100vw - 286px); - white-space: pre-wrap; - word-wrap: break-word; + position: absolute; + top: 53px; + left: 284px; + padding: 8px; + height: calc(100vh - 96px); + font-family: CommitMono Nerd Font !important; + font-size: 14px; + letter-spacing: 1; + border-radius: 10px; + width: calc(100vw - 286px); + white-space: pre-wrap; + word-wrap: break-word; - span { - font-family: CommitMono Nerd Font !important; - } + span { + font-family: CommitMono Nerd Font !important; + } - .full-image { - width: 100%; - aspect-ratio: 16 / 9; - object-fit: cover; - object-position: center; - } + .full-image { + width: 100%; + aspect-ratio: 16 / 9; + object-fit: cover; + object-position: center; + } - .image { - max-width: 100%; - max-height: 100%; - object-fit: contain; - object-position: top left; - } + .image { + max-width: 100%; + max-height: 100%; + object-fit: contain; + object-position: top left; + } } .bottom-bar { - height: 40px; - width: calc(100vw - 2px); - backdrop-filter: blur(18px); - background-color: hsla(40, 3%, 16%, 0.8); - position: fixed; - bottom: 1px; - left: 1px; - z-index: 100; - border-radius: 0 0 12px 12px; - display: flex; - flex-direction: row; - justify-content: space-between; - padding-inline: 12px; - padding-right: 6px; - padding-top: 1px; - align-items: center; - font-size: 14px; - border-top: 1px solid $divider; + height: 40px; + width: calc(100vw - 2px); + backdrop-filter: blur(18px); + background-color: hsla(40, 3%, 16%, 0.8); + position: fixed; + bottom: 1px; + left: 1px; + z-index: 100; + border-radius: 0 0 12px 12px; + display: flex; + flex-direction: row; + justify-content: space-between; + padding-inline: 12px; + padding-right: 6px; + padding-top: 1px; + align-items: center; + font-size: 14px; + border-top: 1px solid $divider; - p { - color: $text2; - } + p { + color: $text2; + } - .left { - display: flex; - align-items: center; - gap: 8px; + .left { + display: flex; + align-items: center; + gap: 8px; - .logo { - width: 18px; - height: 18px; - } - } + .logo { + width: 18px; + height: 18px; + } + } - .right { - display: flex; - align-items: center; + .right { + display: flex; + align-items: center; - .paste p { - color: $text; - } + .paste p { + color: $text; + } - .actions div { - display: flex; - align-items: center; - gap: 2px; - } + .actions div { + display: flex; + align-items: center; + gap: 2px; + } - .divider { - width: 2px; - height: 12px; - background-color: $divider; - margin-left: 8px; - margin-right: 4px; - transition: all 0.2s; - } + .divider { + width: 2px; + height: 12px; + background-color: $divider; + margin-left: 8px; + margin-right: 4px; + transition: all 0.2s; + } - .paste, - .actions { - padding: 4px; - padding-left: 8px; - display: flex; - align-items: center; - gap: 8px; - border-radius: 7px; - background-color: transparent; - transition: all 0.2s; - cursor: pointer; - } + .paste, + .actions { + padding: 4px; + padding-left: 8px; + display: flex; + align-items: center; + gap: 8px; + border-radius: 7px; + background-color: transparent; + transition: all 0.2s; + cursor: pointer; + } - .paste:hover, - .actions:hover { - background-color: $divider; - } + .paste:hover, + .actions:hover { + background-color: $divider; + } - &:hover .paste:hover ~ .divider, - &:hover .actions:hover ~ .divider { - opacity: 0; - } - } + &:hover .paste:hover ~ .divider, + &:hover .actions:hover ~ .divider { + opacity: 0; + } + } } .clothoid-corner { - clip-path: polygon( - 13.890123px 0px, - calc(100% - 13.890123px) 0px, - calc(100% - 12.723414px) 0.004211px, - calc(100% - 11.556933px) 0.025635px, - calc(100% - 10.391895px) 0.085062px, - calc(100% - 9.231074px) 0.199291px, - calc(100% - 8.079275px) 0.382298px, - calc(100% - 6.947448px) 0.662609px, - calc(100% - 5.844179px) 1.039291px, - calc(100% - 4.793324px) 1.542842px, - calc(100% - 3.811369px) 2.169728px, - calc(100% - 2.926417px) 2.926417px, - calc(100% - 2.169728px) 3.811369px, - calc(100% - 1.542842px) 4.793324px, - calc(100% - 1.039291px) 5.844179px, - calc(100% - 0.662609px) 6.947448px, - calc(100% - 0.382298px) 8.079275px, - calc(100% - 0.199291px) 9.231074px, - calc(100% - 0.085062px) 10.391895px, - calc(100% - 0.025635px) 11.556933px, - calc(100% - 0.004211px) 12.723414px, - 100% 13.890123px, - 100% calc(100% - 13.890123px), - calc(100% - 0.004211px) calc(100% - 12.723414px), - calc(100% - 0.025635px) calc(100% - 11.556933px), - calc(100% - 0.085062px) calc(100% - 10.391895px), - calc(100% - 0.199291px) calc(100% - 9.231074px), - calc(100% - 0.382298px) calc(100% - 8.079275px), - calc(100% - 0.662609px) calc(100% - 6.947448px), - calc(100% - 1.039291px) calc(100% - 5.844179px), - calc(100% - 1.542842px) calc(100% - 4.793324px), - calc(100% - 2.169728px) calc(100% - 3.811369px), - calc(100% - 2.926417px) calc(100% - 2.926417px), - calc(100% - 3.811369px) calc(100% - 2.169728px), - calc(100% - 4.793324px) calc(100% - 1.542842px), - calc(100% - 5.844179px) calc(100% - 1.039291px), - calc(100% - 6.947448px) calc(100% - 0.662609px), - calc(100% - 8.079275px) calc(100% - 0.382298px), - calc(100% - 9.231074px) calc(100% - 0.199291px), - calc(100% - 10.391895px) calc(100% - 0.085062px), - calc(100% - 11.556933px) calc(100% - 0.025635px), - calc(100% - 12.723414px) calc(100% - 0.004211px), - calc(100% - 13.890123px) 100%, - 13.890123px 100%, - 12.723414px calc(100% - 0.004211px), - 11.556933px calc(100% - 0.025635px), - 10.391895px calc(100% - 0.085062px), - 9.231074px calc(100% - 0.199291px), - 8.079275px calc(100% - 0.382298px), - 6.947448px calc(100% - 0.662609px), - 5.844179px calc(100% - 1.039291px), - 4.793324px calc(100% - 1.542842px), - 3.811369px calc(100% - 2.169728px), - 2.926417px calc(100% - 2.926417px), - 2.169728px calc(100% - 3.811369px), - 1.542842px calc(100% - 4.793324px), - 1.039291px calc(100% - 5.844179px), - 0.662609px calc(100% - 6.947448px), - 0.382298px calc(100% - 8.079275px), - 0.199291px calc(100% - 9.231074px), - 0.085062px calc(100% - 10.391895px), - 0.025635px calc(100% - 11.556933px), - 0.004211px calc(100% - 12.723414px), - 0px calc(100% - 13.890123px), - 0px 13.890123px, - 0.004211px 12.723414px, - 0.025635px 11.556933px, - 0.085062px 10.391895px, - 0.199291px 9.231074px, - 0.382298px 8.079275px, - 0.662609px 6.947448px, - 1.039291px 5.844179px, - 1.542842px 4.793324px, - 2.169728px 3.811369px, - 2.926417px 2.926417px, - 3.811369px 2.169728px, - 4.793324px 1.542842px, - 5.844179px 1.039291px, - 6.947448px 0.662609px, - 8.079275px 0.382298px, - 9.231074px 0.199291px, - 10.391895px 0.085062px, - 11.556933px 0.025635px, - 12.723414px 0.004211px, - 13.890123px 0px - ); + clip-path: polygon( + 13.890123px 0px, + calc(100% - 13.890123px) 0px, + calc(100% - 12.723414px) 0.004211px, + calc(100% - 11.556933px) 0.025635px, + calc(100% - 10.391895px) 0.085062px, + calc(100% - 9.231074px) 0.199291px, + calc(100% - 8.079275px) 0.382298px, + calc(100% - 6.947448px) 0.662609px, + calc(100% - 5.844179px) 1.039291px, + calc(100% - 4.793324px) 1.542842px, + calc(100% - 3.811369px) 2.169728px, + calc(100% - 2.926417px) 2.926417px, + calc(100% - 2.169728px) 3.811369px, + calc(100% - 1.542842px) 4.793324px, + calc(100% - 1.039291px) 5.844179px, + calc(100% - 0.662609px) 6.947448px, + calc(100% - 0.382298px) 8.079275px, + calc(100% - 0.199291px) 9.231074px, + calc(100% - 0.085062px) 10.391895px, + calc(100% - 0.025635px) 11.556933px, + calc(100% - 0.004211px) 12.723414px, + 100% 13.890123px, + 100% calc(100% - 13.890123px), + calc(100% - 0.004211px) calc(100% - 12.723414px), + calc(100% - 0.025635px) calc(100% - 11.556933px), + calc(100% - 0.085062px) calc(100% - 10.391895px), + calc(100% - 0.199291px) calc(100% - 9.231074px), + calc(100% - 0.382298px) calc(100% - 8.079275px), + calc(100% - 0.662609px) calc(100% - 6.947448px), + calc(100% - 1.039291px) calc(100% - 5.844179px), + calc(100% - 1.542842px) calc(100% - 4.793324px), + calc(100% - 2.169728px) calc(100% - 3.811369px), + calc(100% - 2.926417px) calc(100% - 2.926417px), + calc(100% - 3.811369px) calc(100% - 2.169728px), + calc(100% - 4.793324px) calc(100% - 1.542842px), + calc(100% - 5.844179px) calc(100% - 1.039291px), + calc(100% - 6.947448px) calc(100% - 0.662609px), + calc(100% - 8.079275px) calc(100% - 0.382298px), + calc(100% - 9.231074px) calc(100% - 0.199291px), + calc(100% - 10.391895px) calc(100% - 0.085062px), + calc(100% - 11.556933px) calc(100% - 0.025635px), + calc(100% - 12.723414px) calc(100% - 0.004211px), + calc(100% - 13.890123px) 100%, + 13.890123px 100%, + 12.723414px calc(100% - 0.004211px), + 11.556933px calc(100% - 0.025635px), + 10.391895px calc(100% - 0.085062px), + 9.231074px calc(100% - 0.199291px), + 8.079275px calc(100% - 0.382298px), + 6.947448px calc(100% - 0.662609px), + 5.844179px calc(100% - 1.039291px), + 4.793324px calc(100% - 1.542842px), + 3.811369px calc(100% - 2.169728px), + 2.926417px calc(100% - 2.926417px), + 2.169728px calc(100% - 3.811369px), + 1.542842px calc(100% - 4.793324px), + 1.039291px calc(100% - 5.844179px), + 0.662609px calc(100% - 6.947448px), + 0.382298px calc(100% - 8.079275px), + 0.199291px calc(100% - 9.231074px), + 0.085062px calc(100% - 10.391895px), + 0.025635px calc(100% - 11.556933px), + 0.004211px calc(100% - 12.723414px), + 0px calc(100% - 13.890123px), + 0px 13.890123px, + 0.004211px 12.723414px, + 0.025635px 11.556933px, + 0.085062px 10.391895px, + 0.199291px 9.231074px, + 0.382298px 8.079275px, + 0.662609px 6.947448px, + 1.039291px 5.844179px, + 1.542842px 4.793324px, + 2.169728px 3.811369px, + 2.926417px 2.926417px, + 3.811369px 2.169728px, + 4.793324px 1.542842px, + 5.844179px 1.039291px, + 6.947448px 0.662609px, + 8.079275px 0.382298px, + 9.231074px 0.199291px, + 10.391895px 0.085062px, + 11.556933px 0.025635px, + 12.723414px 0.004211px, + 13.890123px 0px + ); } diff --git a/assets/css/keybind.scss b/assets/css/keybind.scss index 9793148..c3ad9d4 100644 --- a/assets/css/keybind.scss +++ b/assets/css/keybind.scss @@ -1,149 +1,149 @@ -$primary: #2e2d2b; -$accent: #feb453; +$primary: #2E2D2B; +$accent: #FEB453; $divider: #ffffff0d; -$text: #e5dfd5; -$text2: #ada9a1; -$mutedtext: #78756f; +$text: #E5DFD5; +$text2: #ADA9A1; +$mutedtext: #78756F; .bg { - width: 750px; - height: 474px; - background-color: $primary; - border: 1px solid $divider; - border-radius: 12px; - z-index: -1; - position: fixed; - outline: none; + width: 750px; + height: 474px; + background-color: $primary; + border: 1px solid $divider; + border-radius: 12px; + z-index: -1; + position: fixed; + outline: none; } .back { - position: absolute; - top: 16px; - left: 16px; - display: flex; - gap: 8px; - align-items: center; + position: absolute; + top: 16px; + left: 16px; + display: flex; + gap: 8px; + align-items: center; - img { - background-color: $divider; - border-radius: 6px; - padding: 8px 6px; - } + img{ + background-color: $divider; + border-radius: 6px; + padding: 8px 6px; + } - p { - color: $text2; - } + p { + color: $text2; + } } .keybind-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; - gap: 6px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + gap: 6px; - .title { - font-size: 20px; - font-weight: 800; - } + .title { + font-size: 20px; + font-weight: 800; + } - .keybind-input { - padding: 6px; - border: 1px solid $divider; - color: $text2; - display: flex; - border-radius: 13px; - outline: none; - gap: 6px; + .keybind-input { + padding: 6px; + border: 1px solid $divider; + color: $text2; + display: flex; + border-radius: 13px; + outline: none; + gap: 6px; - .key { - color: $text2; - font-family: SFRoundedMedium; - background-color: $divider; - padding: 6px 8px; - border-radius: 8px; - } - } + .key { + color: $text2; + font-family: SFRoundedMedium; + background-color: $divider; + padding: 6px 8px; + border-radius: 8px; + } + } - .keybind-input:focus { - border: 1px solid rgba(255, 255, 255, 0.2); - } + .keybind-input:focus { + border: 1px solid rgba(255, 255, 255, 0.2); + } } .bottom-bar { - height: 40px; - width: calc(100vw - 2px); - backdrop-filter: blur(18px); - background-color: hsla(40, 3%, 16%, 0.8); - position: fixed; - bottom: 1px; - left: 1px; - z-index: 100; - border-radius: 0 0 12px 12px; - display: flex; - flex-direction: row; - justify-content: space-between; - padding-inline: 12px; - padding-right: 6px; - padding-top: 1px; - align-items: center; - font-size: 14px; - border-top: 1px solid $divider; + height: 40px; + width: calc(100vw - 2px); + backdrop-filter: blur(18px); + background-color: hsla(40, 3%, 16%, 0.8); + position: fixed; + bottom: 1px; + left: 1px; + z-index: 100; + border-radius: 0 0 12px 12px; + display: flex; + flex-direction: row; + justify-content: space-between; + padding-inline: 12px; + padding-right: 6px; + padding-top: 1px; + align-items: center; + font-size: 14px; + border-top: 1px solid $divider; - p { - color: $text2; - } + p { + color: $text2; + } - .left { - display: flex; - align-items: center; - gap: 8px; + .left { + display: flex; + align-items: center; + gap: 8px; - .logo { - width: 18px; - height: 18px; - } - } + .logo { + width: 18px; + height: 18px; + } + } - .right { - display: flex; - align-items: center; + .right { + display: flex; + align-items: center; - .actions div { - display: flex; - align-items: center; - gap: 2px; - } + .actions div { + display: flex; + align-items: center; + gap: 2px; + } - .divider { - width: 2px; - height: 12px; - background-color: $divider; - margin-left: 8px; - margin-right: 4px; - transition: all 0.2s; - } + .divider { + width: 2px; + height: 12px; + background-color: $divider; + margin-left: 8px; + margin-right: 4px; + transition: all .2s; + } - .actions { - padding: 4px; - padding-left: 8px; - display: flex; - align-items: center; - gap: 8px; - border-radius: 7px; - background-color: transparent; - transition: all 0.2s; - cursor: pointer; - } + .actions { + padding: 4px; + padding-left: 8px; + display: flex; + align-items: center; + gap: 8px; + border-radius: 7px; + background-color: transparent; + transition: all .2s; + cursor: pointer; + } - .actions:hover { - background-color: $divider; - } + .actions:hover { + background-color: $divider; + } - &:hover .actions:hover ~ .divider { - opacity: 0; - } - } -} + &:hover .actions:hover~.divider { + opacity: 0; + } + } +} \ No newline at end of file diff --git a/components/Noise.vue b/components/Noise.vue index 6f99508..41bb879 100644 --- a/components/Noise.vue +++ b/components/Noise.vue @@ -1,9 +1,9 @@ + \ No newline at end of file diff --git a/nuxt.config.ts b/nuxt.config.ts index 8625c3b..071a2b2 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,15 +1,15 @@ // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ - devtools: { enabled: false }, - compatibilityDate: "2024-07-04", - ssr: false, - vite: { - css: { - preprocessorOptions: { - scss: { - api: "modern-compiler", - }, - }, - }, - }, + devtools: { enabled: false }, + compatibilityDate: "2024-07-04", + ssr: false, + vite: { + css: { + preprocessorOptions: { + scss: { + api: "modern-compiler", + }, + }, + }, + }, }); diff --git a/package.json b/package.json index 912abfe..172bbb1 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,26 @@ { - "name": "nuxt-app", - "dependencies": { - "@tauri-apps/api": "2.1.1", - "@tauri-apps/cli": "2.1.0", - "@tauri-apps/plugin-autostart": "2.0.0", - "@tauri-apps/plugin-fs": "2.0.2", - "@tauri-apps/plugin-os": "2.0.0", - "@tauri-apps/plugin-sql": "2.0.1", - "nuxt": "3.14.1592", - "nuxt-build-cache": "0.1.1", - "overlayscrollbars": "2.10.0", - "overlayscrollbars-vue": "0.5.9", - "prettier": "^3.3.3", - "sass": "1.81.0", - "vue": "3.5.13" - }, - "private": true, - "scripts": { - "build": "tauri build", - "dev": "tauri dev", - "generate": "nuxt generate", - "preview": "nuxt preview", - "postinstall": "nuxt prepare", - "format": "prettier --write \"**/*.{js,ts,vue,scss,css,json,md}\"" - }, - "type": "module", - "devDependencies": { - "prettier-plugin-vue": "^1.1.6" - } -} + "name": "nuxt-app", + "private": true, + "type": "module", + "scripts": { + "build": "tauri build", + "dev": "tauri dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare" + }, + "dependencies": { + "@tauri-apps/api": "2.0.3", + "@tauri-apps/cli": "2.1.0", + "@tauri-apps/plugin-autostart": "2.0.0", + "@tauri-apps/plugin-fs": "2.0.2", + "@tauri-apps/plugin-os": "2.0.0", + "@tauri-apps/plugin-sql": "2.0.1", + "nuxt": "3.14.159", + "nuxt-build-cache": "0.1.1", + "overlayscrollbars": "2.10.0", + "overlayscrollbars-vue": "0.5.9", + "sass": "1.81.0", + "vue": "3.5.13" + } +} \ No newline at end of file diff --git a/pages/index.vue b/pages/index.vue index a0d295c..559e557 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,570 +1,533 @@ diff --git a/pages/keybind.vue b/pages/keybind.vue index ccc5952..c097a2e 100644 --- a/pages/keybind.vue +++ b/pages/keybind.vue @@ -1,185 +1,176 @@ +@use '~/assets/css/keybind.scss'; + \ No newline at end of file diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index a133ffc..65205ee 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4508,9 +4508,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa 1.0.11", "memchr", @@ -6082,9 +6082,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", "idna", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index deb0af7..5f4e589 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.70" tauri-build = { version = "2.0.3", features = [] } [dependencies] -tauri = { version = "2.1.1", features = [ +tauri = { version = "2.0.1", features = [ "macos-private-api", "tray-icon", "image-png", @@ -27,17 +27,17 @@ tauri-plugin-global-shortcut = "2.0.1" sqlx = { version = "0.8.2", features = ["runtime-tokio-native-tls", "sqlite"] } serde = { version = "1.0.215", features = ["derive"] } tokio = { version = "1.41.1", features = ["full"] } -serde_json = "1.0.133" +serde_json = "1.0.132" rdev = "0.5.3" -rand = "0.8.5" +rand = "0.8" base64 = "0.22.1" image = "0.25.5" reqwest = { version = "0.12.9", features = ["blocking"] } -url = "2.5.4" +url = "2.5.3" regex = "1.11.1" -sha2 = "0.10.8" -lazy_static = "1.5.0" -time = "0.3.36" +sha2 = "0.10.6" +lazy_static = "1.4.0" +time = "0.3" global-hotkey = "0.6.3" [features] diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index cf9ae1a..883a577 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -1,32 +1,34 @@ { - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "enables the default permissions", - "windows": ["main"], - "permissions": [ - "core:path:default", - "core:event:default", - "core:window:default", - "core:webview:default", - "core:app:default", - "core:resources:default", - "core:image:default", - "core:menu:default", - "core:tray:default", - "sql:allow-load", - "sql:allow-select", - "sql:allow-execute", - "autostart:allow-enable", - "autostart:allow-disable", - "autostart:allow-is-enabled", - "os:allow-os-type", - "core:app:allow-app-hide", - "core:app:allow-app-show", - "core:window:allow-hide", - "core:window:allow-show", - "core:window:allow-set-focus", - "core:window:allow-is-focused", - "core:window:allow-is-visible", - "fs:allow-read" - ] -} + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": [ + "main" + ], + "permissions": [ + "core:path:default", + "core:event:default", + "core:window:default", + "core:webview:default", + "core:app:default", + "core:resources:default", + "core:image:default", + "core:menu:default", + "core:tray:default", + "sql:allow-load", + "sql:allow-select", + "sql:allow-execute", + "autostart:allow-enable", + "autostart:allow-disable", + "autostart:allow-is-enabled", + "os:allow-os-type", + "core:app:allow-app-hide", + "core:app:allow-app-show", + "core:window:allow-hide", + "core:window:allow-show", + "core:window:allow-set-focus", + "core:window:allow-is-focused", + "core:window:allow-is-visible", + "fs:allow-read" + ] +} \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 68ed873..19c975b 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -6,7 +6,6 @@ mod api; mod utils; -use tauri::window::{Effect, EffectState, EffectsBuilder}; use tauri::Manager; use tauri::WebviewUrl; use tauri::WebviewWindow; @@ -46,9 +45,7 @@ fn main() { .visible(false) .decorations(false) .transparent(true) - .always_on_top(true) - .content_protected(true) - .visible_on_all_workspaces(true) + .always_on_top(false) .build()? }; @@ -71,13 +68,6 @@ fn main() { api::updater::check_for_updates(app_handle).await; }); - main_window.set_effects( - EffectsBuilder::new() - .effect(Effect::Popover) - .state(EffectState::Active) - .build(), - )?; - Ok(()) }) .on_window_event(|_app, _event| { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index e05fc4f..a277188 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,58 +1,60 @@ { - "productName": "Qopy", - "version": "0.2.1", - "identifier": "net.pandadev.qopy", - "build": { - "frontendDist": "../dist", - "devUrl": "http://localhost:3000", - "beforeDevCommand": "pnpm nuxt dev", - "beforeBuildCommand": "pnpm nuxt generate" - }, - "app": { - "windows": [ - { - "title": "Qopy", - "titleBarStyle": "Overlay", - "fullscreen": false, - "resizable": false, - "height": 474, - "width": 750, - "minHeight": 474, - "maxHeight": 474, - "minWidth": 750, - "maxWidth": 750, - "decorations": false, - "center": true, - "shadow": false, - "transparent": true, - "skipTaskbar": true, - "alwaysOnTop": true - } - ], - "security": { - "csp": null - }, - "withGlobalTauri": true, - "macOSPrivateApi": true - }, - "bundle": { - "createUpdaterArtifacts": true, - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "category": "DeveloperTool" - }, - "plugins": { - "updater": { - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDExNDIzNjA1QjE0NjU1OTkKUldTWlZVYXhCVFpDRWNvNmt0UE5lQmZkblEyZGZiZ2tHelJvT2YvNVpLU1RIM1RKZFQrb2tzWWwK", - "endpoints": ["https://qopy.pandadev.net/"] - } - }, - "$schema": "../node_modules/@tauri-apps/cli/schema.json" + "productName": "Qopy", + "version": "0.2.0", + "identifier": "net.pandadev.qopy", + "build": { + "frontendDist": "../dist", + "devUrl": "http://localhost:3000", + "beforeDevCommand": "pnpm nuxt dev", + "beforeBuildCommand": "pnpm nuxt generate" + }, + "app": { + "windows": [ + { + "title": "Qopy", + "titleBarStyle": "Overlay", + "fullscreen": false, + "resizable": false, + "height": 474, + "width": 750, + "minHeight": 474, + "maxHeight": 474, + "minWidth": 750, + "maxWidth": 750, + "decorations": false, + "center": true, + "shadow": false, + "transparent": true, + "skipTaskbar": true, + "alwaysOnTop": true + } + ], + "security": { + "csp": null + }, + "withGlobalTauri": true, + "macOSPrivateApi": true + }, + "bundle": { + "createUpdaterArtifacts": true, + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "category": "DeveloperTool" + }, + "plugins": { + "updater": { + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDExNDIzNjA1QjE0NjU1OTkKUldTWlZVYXhCVFpDRWNvNmt0UE5lQmZkblEyZGZiZ2tHelJvT2YvNVpLU1RIM1RKZFQrb2tzWWwK", + "endpoints": [ + "https://qopy.pandadev.net/" + ] + } + }, + "$schema": "../node_modules/@tauri-apps/cli/schema.json" } diff --git a/tsconfig.json b/tsconfig.json index 947f6b6..a746f2a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,4 @@ { - // https://nuxt.com/docs/guide/concepts/typescript - "extends": "./.nuxt/tsconfig.json" + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" } From 78e747fb06dd0203efbd24e3cf016b7243373f4e Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:12:45 +1000 Subject: [PATCH 010/180] feat: release action --- .github/workflows/release.yml | 214 ++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a830b38 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,214 @@ +name: "Release" + +on: + push: + tags: + - "v*" + workflow_dispatch: + +jobs: + prepare: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.get_version.outputs.VERSION }} + steps: + - uses: actions/checkout@v4 + - name: Get version + id: get_version + run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT + + build-macos: + needs: prepare + strategy: + matrix: + include: + - args: "--target aarch64-apple-darwin" + arch: "silicon" + - args: "--target x86_64-apple-darwin" + arch: "intel" + runs-on: macos-latest + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + steps: + - uses: actions/checkout@v4 + - name: Redact Sensitive Information + run: | + function redact_output { + sed -e "s/${{ secrets.REDACT_PATTERN }}/REDACTED/g" + } + exec > >(redact_output) 2>&1 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-apple-darwin,x86_64-apple-darwin + - uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri -> target" + cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" + shared-key: "macos-rust-cache" + save-if: "true" + - uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + - run: npm install -g pnpm && pnpm install + - name: Import Apple Developer Certificate + env: + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 + security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain + security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} + TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} + with: + args: ${{ matrix.args }} + tagName: v${{ needs.prepare.outputs.version }} + releaseName: v${{ needs.prepare.outputs.version }} + releaseBody: "See the assets to download this version and install." + releaseDraft: true + prerelease: false + - name: Rename macOS Artifacts + run: | + mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/*.dmg src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.dmg + mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz + mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz.sig src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz.sig + + build-windows: + needs: prepare + strategy: + matrix: + include: + - args: "--target x86_64-pc-windows-msvc" + arch: "x64" + - args: "--target aarch64-pc-windows-msvc" + arch: "arm64" + runs-on: windows-latest + env: + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-pc-windows-msvc,aarch64-pc-windows-msvc + - uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri -> target" + cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" + shared-key: "windows-rust-cache" + save-if: "true" + - uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + - run: npm install -g pnpm && pnpm install + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: ${{ matrix.args }} + tagName: v${{ needs.prepare.outputs.version }} + releaseName: v${{ needs.prepare.outputs.version }} + releaseBody: "See the assets to download this version and install." + releaseDraft: true + prerelease: false + - name: Rename Windows Artifacts + run: | + mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi + mv src-tauri/target/release/bundle/msi/*.msi.sig src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig + + build-linux: + needs: prepare + runs-on: ubuntu-latest + env: + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: dtolnay/rust-toolchain@stable + - uses: swatinem/rust-cache@v2 + with: + workspaces: "src-tauri -> target" + cache-directories: "~/.cargo/registry/index/,~/.cargo/registry/cache/,~/.cargo/git/db/" + shared-key: "linux-rust-cache" + save-if: "true" + - uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y libwebkit2gtk-4.1-dev build-essential curl wget file libssl-dev libayatana-appindicator3-dev librsvg2-dev libasound2-dev rpm + echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV + - run: npm install -g pnpm && pnpm install + - name: Generate Changelog + id: changelog + run: | + CHANGELOG=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") + echo "CHANGELOG<> $GITHUB_ENV + echo "$CHANGELOG" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: --target x86_64-unknown-linux-gnu + tagName: v${{ needs.prepare.outputs.version }} + releaseName: v${{ needs.prepare.outputs.version }} + releaseBody: | + ## Changelog + ${{ env.CHANGELOG }} + + See the assets to download this version and install. + releaseDraft: true + prerelease: false + - name: Rename Linux Artifacts + run: | + mv src-tauri/target/release/bundle/deb/*.deb src-tauri/target/release/bundle/deb/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb + mv src-tauri/target/release/bundle/appimage/*.AppImage src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage + mv src-tauri/target/release/bundle/appimage/*.AppImage.sig src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage.sig + mv src-tauri/target/release/bundle/rpm/*.rpm src-tauri/target/release/bundle/rpm/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm + - name: Create Draft Release + uses: softprops/action-gh-release@v1 + with: + draft: true + files: | + src-tauri/target/release/bundle/deb/*.deb + src-tauri/target/release/bundle/appimage/*.AppImage + src-tauri/target/release/bundle/appimage/*.AppImage.sig + src-tauri/target/release/bundle/rpm/*.rpm + body: | + ## Changelog + ${{ env.CHANGELOG }} + + See the assets to download this version and install. + tag_name: v${{ needs.prepare.outputs.version }} + name: v${{ needs.prepare.outputs.version }} \ No newline at end of file From 1d1ac8ace7bd9ceae64de7bc73160a608145330d Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:26:49 +1000 Subject: [PATCH 011/180] fix: permission build error --- .github/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a830b38..b7c8e65 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,7 @@ on: jobs: prepare: + permissions: write-all runs-on: ubuntu-latest outputs: version: ${{ steps.get_version.outputs.VERSION }} @@ -18,6 +19,7 @@ jobs: run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT build-macos: + permissions: write-all needs: prepare strategy: matrix: @@ -91,6 +93,7 @@ jobs: mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz.sig src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz.sig build-windows: + permissions: write-all needs: prepare strategy: matrix: @@ -139,6 +142,7 @@ jobs: mv src-tauri/target/release/bundle/msi/*.msi.sig src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig build-linux: + permissions: write-all needs: prepare runs-on: ubuntu-latest env: From cdbdca10a2d93708fb52dfff91d230ed250bfdd1 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 12:15:10 +1000 Subject: [PATCH 012/180] feat: moved release job --- .github/workflows/release.yml | 66 ++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b7c8e65..3411445 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,11 +81,7 @@ jobs: TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} with: args: ${{ matrix.args }} - tagName: v${{ needs.prepare.outputs.version }} - releaseName: v${{ needs.prepare.outputs.version }} - releaseBody: "See the assets to download this version and install." - releaseDraft: true - prerelease: false + - name: Rename macOS Artifacts run: | mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/*.dmg src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.dmg @@ -131,11 +127,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: args: ${{ matrix.args }} - tagName: v${{ needs.prepare.outputs.version }} - releaseName: v${{ needs.prepare.outputs.version }} - releaseBody: "See the assets to download this version and install." - releaseDraft: true - prerelease: false + - name: Rename Windows Artifacts run: | mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi @@ -185,30 +177,46 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: args: --target x86_64-unknown-linux-gnu - tagName: v${{ needs.prepare.outputs.version }} - releaseName: v${{ needs.prepare.outputs.version }} - releaseBody: | - ## Changelog - ${{ env.CHANGELOG }} - - See the assets to download this version and install. - releaseDraft: true - prerelease: false - name: Rename Linux Artifacts run: | - mv src-tauri/target/release/bundle/deb/*.deb src-tauri/target/release/bundle/deb/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb - mv src-tauri/target/release/bundle/appimage/*.AppImage src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage - mv src-tauri/target/release/bundle/appimage/*.AppImage.sig src-tauri/target/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage.sig - mv src-tauri/target/release/bundle/rpm/*.rpm src-tauri/target/release/bundle/rpm/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm - - name: Create Draft Release + mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb + mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage + mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage.sig src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage.sig + mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/rpm/*.rpm src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/rpm/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm + - name: Upload Linux artifacts + uses: actions/upload-artifact@v4 + with: + name: linux-artifacts + path: | + src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb + src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage + src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage.sig + src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/rpm/*.rpm + + create-release: + permissions: write-all + needs: [prepare, build-macos, build-windows, build-linux] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + - name: Generate Changelog + id: changelog + run: | + CHANGELOG=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") + echo "CHANGELOG<> $GITHUB_ENV + echo "$CHANGELOG" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - name: Create Release uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: draft: true - files: | - src-tauri/target/release/bundle/deb/*.deb - src-tauri/target/release/bundle/appimage/*.AppImage - src-tauri/target/release/bundle/appimage/*.AppImage.sig - src-tauri/target/release/bundle/rpm/*.rpm + files: artifacts/**/* body: | ## Changelog ${{ env.CHANGELOG }} From 0a66c8cbff749f3a21811cd6259bd4274c36e0be Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 12:15:26 +1000 Subject: [PATCH 013/180] chore: package updates --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 172bbb1..d4c6e94 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,13 @@ "postinstall": "nuxt prepare" }, "dependencies": { - "@tauri-apps/api": "2.0.3", + "@tauri-apps/api": "2.1.1", "@tauri-apps/cli": "2.1.0", "@tauri-apps/plugin-autostart": "2.0.0", "@tauri-apps/plugin-fs": "2.0.2", "@tauri-apps/plugin-os": "2.0.0", "@tauri-apps/plugin-sql": "2.0.1", - "nuxt": "3.14.159", + "nuxt": "3.14.1592", "nuxt-build-cache": "0.1.1", "overlayscrollbars": "2.10.0", "overlayscrollbars-vue": "0.5.9", From 3fad37c6d2a59ac4bd879619fb7df5e56ed02535 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 12:30:47 +1000 Subject: [PATCH 014/180] fix: remaning binaries on windows --- .github/workflows/release.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3411445..dc9d52f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,8 +130,14 @@ jobs: - name: Rename Windows Artifacts run: | - mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi - mv src-tauri/target/release/bundle/msi/*.msi.sig src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig + mv src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/*.msi src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi + mv src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/*.msi.sig src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig + + - name: Upload Windows artifacts + uses: actions/upload-artifact@v4 + with: + name: windows-artifacts + path: src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/* build-linux: permissions: write-all From ff5081308cac6839b10548c6eed330370dee1826 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 12:52:39 +1000 Subject: [PATCH 015/180] fix: windows build error --- .github/workflows/release.yml | 39 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dc9d52f..b9301f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,7 +86,13 @@ jobs: run: | mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/*.dmg src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.dmg mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz - mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz.sig src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz.sig + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: macos-${{ matrix.arch }}-binaries + path: | + src-tauri/target/**/release/bundle/dmg/*.dmg + src-tauri/target/**/release/bundle/macos/*.app.tar.gz build-windows: permissions: write-all @@ -130,14 +136,13 @@ jobs: - name: Rename Windows Artifacts run: | - mv src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/*.msi src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi - mv src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/*.msi.sig src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi.sig - - - name: Upload Windows artifacts + mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi + - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: windows-artifacts - path: src-tauri/target/${{ matrix.args == '--target aarch64-pc-windows-msvc' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}/release/bundle/msi/* + name: windows-${{ matrix.arch }}-binaries + path: | + src-tauri/target/release/bundle/msi/*.msi build-linux: permissions: write-all @@ -187,16 +192,14 @@ jobs: run: | mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage - mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage.sig src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage.sig mv src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/rpm/*.rpm src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/rpm/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm - - name: Upload Linux artifacts + - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: linux-artifacts + name: linux-binaries path: | src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage - src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage.sig src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/rpm/*.rpm create-release: @@ -222,11 +225,17 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: draft: true - files: artifacts/**/* + tag_name: v${{ needs.prepare.outputs.version }} + name: v${{ needs.prepare.outputs.version }} + files: | + artifacts/**/*.dmg + artifacts/**/*.app.tar.gz + artifacts/**/*.msi + artifacts/**/*.deb + artifacts/**/*.AppImage + artifacts/**/*.rpm body: | ## Changelog ${{ env.CHANGELOG }} - See the assets to download this version and install. - tag_name: v${{ needs.prepare.outputs.version }} - name: v${{ needs.prepare.outputs.version }} \ No newline at end of file + See the assets to download this version and install. \ No newline at end of file From 89b67f24f251673ff315be60a2ed6bc630057844 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 15:17:39 +1000 Subject: [PATCH 016/180] fix: renaming of files --- .github/workflows/release.yml | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b9301f7..188dda7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -133,10 +133,32 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: args: ${{ matrix.args }} - - - name: Rename Windows Artifacts + - name: List Bundle Directory + shell: pwsh run: | - mv src-tauri/target/release/bundle/msi/*.msi src-tauri/target/release/bundle/msi/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.msi + $bundlePath = "src-tauri/target/release/bundle/msi" + if (Test-Path $bundlePath) { + Write-Output "Contents of $bundlePath:" + Get-ChildItem -Path $bundlePath + } else { + Write-Output "Path $bundlePath does not exist." + } + - name: Rename Windows Artifacts + shell: pwsh + run: | + $bundlePath = "src-tauri/target/release/bundle/msi" + $version = "${{ needs.prepare.outputs.version }}" + $arch = "${{ matrix.arch }}" + if (Test-Path $bundlePath) { + $msiFiles = Get-ChildItem -Path "$bundlePath/*.msi" + foreach ($file in $msiFiles) { + $newName = "Qopy-$version`_$arch.msi" + Rename-Item -Path $file.FullName -NewName $newName + } + } else { + Write-Error "Path $bundlePath does not exist." + exit 1 + } - name: Upload artifacts uses: actions/upload-artifact@v4 with: From 999b9bada285336474c8b5b7979b5a7ce185b4a7 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 16:57:44 +1000 Subject: [PATCH 017/180] fix: action error --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 188dda7..ae51ae9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -138,10 +138,10 @@ jobs: run: | $bundlePath = "src-tauri/target/release/bundle/msi" if (Test-Path $bundlePath) { - Write-Output "Contents of $bundlePath:" + Write-Output "Contents of ${bundlePath}:" Get-ChildItem -Path $bundlePath } else { - Write-Output "Path $bundlePath does not exist." + Write-Output "Path ${bundlePath} does not exist." } - name: Rename Windows Artifacts shell: pwsh @@ -156,7 +156,7 @@ jobs: Rename-Item -Path $file.FullName -NewName $newName } } else { - Write-Error "Path $bundlePath does not exist." + Write-Error "Path ${bundlePath} does not exist." exit 1 } - name: Upload artifacts From c20f01eb489caee1dc38e4f912ecf461805690ac Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:00:53 +1000 Subject: [PATCH 018/180] docs: readme refining --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f7698f..5eeaf9f 100644 --- a/README.md +++ b/README.md @@ -61,11 +61,11 @@ Qopy is a fixed clipboard manager designed as a simple alternative to the standa ## 🚧 Roadmap - [ ] [Setup guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md) +- [ ] Sync Clipboard across devices https://github.com/0PandaDEV/Qopy/issues/8 - [ ] Settings https://github.com/0PandaDEV/Qopy/issues/2 - [ ] Metadata for copied items https://github.com/0PandaDEV/Qopy/issues/5 - [ ] Code highlighting https://github.com/0PandaDEV/Qopy/issues/7 - [ ] Streamshare integration https://github.com/0PandaDEV/Qopy/issues/4 -- [ ] Cross-device clipboard sharing https://github.com/0PandaDEV/Qopy/issues/8 - [x] Option for custom keybind https://github.com/0PandaDEV/Qopy/issues/3 - [x] macOS Support https://github.com/0PandaDEV/Qopy/issues/13 From dab8394dd422da9cf367d1275661286adce7f7bc Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:14:57 +1000 Subject: [PATCH 019/180] chore(actions): file not found --- .github/workflows/release.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ae51ae9..ef5b6d9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -102,8 +102,10 @@ jobs: include: - args: "--target x86_64-pc-windows-msvc" arch: "x64" + target: "x86_64-pc-windows-msvc" - args: "--target aarch64-pc-windows-msvc" arch: "arm64" + target: "aarch64-pc-windows-msvc" runs-on: windows-latest env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} @@ -136,7 +138,7 @@ jobs: - name: List Bundle Directory shell: pwsh run: | - $bundlePath = "src-tauri/target/release/bundle/msi" + $bundlePath = "src-tauri/target/${{ matrix.target }}/release/bundle/msi" if (Test-Path $bundlePath) { Write-Output "Contents of ${bundlePath}:" Get-ChildItem -Path $bundlePath @@ -146,7 +148,7 @@ jobs: - name: Rename Windows Artifacts shell: pwsh run: | - $bundlePath = "src-tauri/target/release/bundle/msi" + $bundlePath = "src-tauri/target/${{ matrix.target }}/release/bundle/msi" $version = "${{ needs.prepare.outputs.version }}" $arch = "${{ matrix.arch }}" if (Test-Path $bundlePath) { @@ -163,8 +165,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: windows-${{ matrix.arch }}-binaries - path: | - src-tauri/target/release/bundle/msi/*.msi + path: src-tauri/target/${{ matrix.target }}/release/bundle/msi/*.msi build-linux: permissions: write-all From 93918c4749c2c0155094bf525e09ea21648f1051 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:50:13 +1000 Subject: [PATCH 020/180] feat: new version 0.2.1 --- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 65205ee..bd7b306 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3811,7 +3811,7 @@ dependencies = [ [[package]] name = "qopy" -version = "0.2.0" +version = "0.2.1" dependencies = [ "base64 0.22.1", "global-hotkey", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5f4e589..843199c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "qopy" -version = "0.2.0" +version = "0.2.1" description = "Qopy" authors = ["pandadev"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index a277188..eb05567 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,6 +1,6 @@ { "productName": "Qopy", - "version": "0.2.0", + "version": "0.2.1", "identifier": "net.pandadev.qopy", "build": { "frontendDist": "../dist", From 5addcef5a7b6ab034dc6a9270d78fd6f4d5d7645 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 18:33:53 +1000 Subject: [PATCH 021/180] chore(actions): release body --- .github/workflows/release.yml | 45 +++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ef5b6d9..be32f58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v4 - name: Get version id: get_version - run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT + run: echo "VERSION=$(node -p \"require('./src-tauri/tauri.conf.json').version\")" >> $GITHUB_OUTPUT build-macos: permissions: write-all @@ -85,14 +85,12 @@ jobs: - name: Rename macOS Artifacts run: | mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/*.dmg src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/dmg/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.dmg - mv src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/*.app.tar.gz src-tauri/target/${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}/release/bundle/macos/Qopy-${{ needs.prepare.outputs.version }}_${{ matrix.arch }}.app.tar.gz - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: macos-${{ matrix.arch }}-binaries path: | src-tauri/target/**/release/bundle/dmg/*.dmg - src-tauri/target/**/release/bundle/macos/*.app.tar.gz build-windows: permissions: write-all @@ -235,13 +233,35 @@ jobs: uses: actions/download-artifact@v4 with: path: artifacts - - name: Generate Changelog - id: changelog + - name: Generate Release Body + id: release_body run: | - CHANGELOG=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") - echo "CHANGELOG<> $GITHUB_ENV - echo "$CHANGELOG" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV + VERSION=${{ needs.prepare.outputs.version }} + CHANGES=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") + + # Calculate SHA256 hashes for each artifact + WINDOWS_HASH=$(sha256sum artifacts/windows-x64-binaries/Qopy-$VERSION_x64.msi | awk '{ print $1 }') + MAC_SILICON_HASH=$(sha256sum artifacts/macos-silicon-binaries/Qopy-$VERSION_silicon.dmg | awk '{ print $1 }') + MAC_INTEL_HASH=$(sha256sum artifacts/macos-intel-binaries/Qopy-$VERSION_intel.dmg | awk '{ print $1 }') + DEBIAN_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.deb | awk '{ print $1 }') + APPIMAGE_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.AppImage | awk '{ print $1 }') + REDHAT_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.rpm | awk '{ print $1 }') + + ## ♻️ Changelog + + $CHANGES + + ⬇️ Downloads + + - [Windows (x64)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_x64.msi) - $WINDOWS_HASH + - [Windows (ARM64)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_arm64.msi) - $WINDOWS_HASH + - [macOS (Silicon)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_silicon.dmg) - $MAC_SILICON_HASH + - [macOS (Intel)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_intel.dmg) - $MAC_INTEL_HASH + - [Debian](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb) - $DEBIAN_HASH + - [AppImage](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_amd64.AppImage) - $APPIMAGE_HASH + - [Red Hat](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_amd64.rpm) - $REDHAT_HASH" + + echo "RELEASE_BODY=$RELEASE_BODY" >> $GITHUB_ENV - name: Create Release uses: softprops/action-gh-release@v1 env: @@ -252,13 +272,8 @@ jobs: name: v${{ needs.prepare.outputs.version }} files: | artifacts/**/*.dmg - artifacts/**/*.app.tar.gz artifacts/**/*.msi artifacts/**/*.deb artifacts/**/*.AppImage artifacts/**/*.rpm - body: | - ## Changelog - ${{ env.CHANGELOG }} - - See the assets to download this version and install. \ No newline at end of file + body: ${{ env.RELEASE_BODY }} \ No newline at end of file From 469897620b92967ef4c8f3a634ace9c4169c0e80 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 18:36:02 +1000 Subject: [PATCH 022/180] fix: build error --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index be32f58..472ff28 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v4 - name: Get version id: get_version - run: echo "VERSION=$(node -p \"require('./src-tauri/tauri.conf.json').version\")" >> $GITHUB_OUTPUT + run: echo "VERSION=$(node -p 'require(\"./src-tauri/tauri.conf.json\").version')" >> $GITHUB_OUTPUT build-macos: permissions: write-all @@ -263,7 +263,7 @@ jobs: echo "RELEASE_BODY=$RELEASE_BODY" >> $GITHUB_ENV - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: From fcc310b80ab16c0125a64d270d2f5127bcb89ec4 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Sun, 24 Nov 2024 18:56:11 +1000 Subject: [PATCH 023/180] fix: windows arm release body --- .github/workflows/release.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 472ff28..0c4836b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,9 @@ jobs: - uses: actions/checkout@v4 - name: Get version id: get_version - run: echo "VERSION=$(node -p 'require(\"./src-tauri/tauri.conf.json\").version')" >> $GITHUB_OUTPUT + run: | + VERSION=$(node -p 'require("./src-tauri/tauri.conf.json").version') + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT build-macos: permissions: write-all @@ -240,7 +242,8 @@ jobs: CHANGES=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") # Calculate SHA256 hashes for each artifact - WINDOWS_HASH=$(sha256sum artifacts/windows-x64-binaries/Qopy-$VERSION_x64.msi | awk '{ print $1 }') + WINDOWS_ARM_HASH=$(sha256sum artifacts/windows-arm64-binaries/Qopy-$VERSION_arm64.msi | awk '{ print $1 }') + WINDOWS_64_HASH=$(sha256sum artifacts/windows-x64-binaries/Qopy-$VERSION_x64.msi | awk '{ print $1 }') MAC_SILICON_HASH=$(sha256sum artifacts/macos-silicon-binaries/Qopy-$VERSION_silicon.dmg | awk '{ print $1 }') MAC_INTEL_HASH=$(sha256sum artifacts/macos-intel-binaries/Qopy-$VERSION_intel.dmg | awk '{ print $1 }') DEBIAN_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.deb | awk '{ print $1 }') @@ -253,8 +256,8 @@ jobs: ⬇️ Downloads - - [Windows (x64)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_x64.msi) - $WINDOWS_HASH - - [Windows (ARM64)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_arm64.msi) - $WINDOWS_HASH + - [Windows (x64)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_x64.msi) - $WINDOWS_64_HASH + - [Windows (ARM64)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_arm64.msi) - $WINDOWS_ARM_HASH - [macOS (Silicon)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_silicon.dmg) - $MAC_SILICON_HASH - [macOS (Intel)](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_intel.dmg) - $MAC_INTEL_HASH - [Debian](https://github.com/${{ github.repository }}/releases/download/v${{ needs.prepare.outputs.version }}/Qopy-${{ needs.prepare.outputs.version }}_amd64.deb) - $DEBIAN_HASH From 9162033b655bcb3ba47a5d0f14ce4312e18dc325 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:23:36 +1000 Subject: [PATCH 024/180] chore(actions): fix command not found --- .github/workflows/release.yml | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c4836b..faa518a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -231,16 +231,20 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts + - name: Generate Release Body id: release_body run: | VERSION=${{ needs.prepare.outputs.version }} CHANGES=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") - + # Calculate SHA256 hashes for each artifact WINDOWS_ARM_HASH=$(sha256sum artifacts/windows-arm64-binaries/Qopy-$VERSION_arm64.msi | awk '{ print $1 }') WINDOWS_64_HASH=$(sha256sum artifacts/windows-x64-binaries/Qopy-$VERSION_x64.msi | awk '{ print $1 }') @@ -249,22 +253,26 @@ jobs: DEBIAN_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.deb | awk '{ print $1 }') APPIMAGE_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.AppImage | awk '{ print $1 }') REDHAT_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.rpm | awk '{ print $1 }') - + + RELEASE_BODY=$(cat <> $GITHUB_ENV + - name: Create Release uses: softprops/action-gh-release@v2 env: From 3195cd80b47820cb226e27da5d5294337d570dda Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:53:17 +1000 Subject: [PATCH 025/180] chore(actions): fix invalid format --- .github/workflows/release.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index faa518a..9714398 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -254,13 +254,13 @@ jobs: APPIMAGE_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.AppImage | awk '{ print $1 }') REDHAT_HASH=$(sha256sum artifacts/linux-binaries/Qopy-$VERSION_amd64.rpm | awk '{ print $1 }') - RELEASE_BODY=$(cat <> $GITHUB_ENV + echo "RELEASE_BODY<> $GITHUB_ENV + echo "$RELEASE_BODY" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV - name: Create Release uses: softprops/action-gh-release@v2 From 2f88644005eb11e7c7fe4ea5b31e8aec3d6f9625 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:34:44 +1000 Subject: [PATCH 026/180] fix: missing bracket --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9714398..7831f2c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -269,6 +269,7 @@ jobs: - [AppImage](https://github.com/${{ github.repository }}/releases/download/v$VERSION/Qopy-$VERSION_amd64.AppImage) - $APPIMAGE_HASH - [Red Hat](https://github.com/${{ github.repository }}/releases/download/v$VERSION/Qopy-$VERSION_amd64.rpm) - $REDHAT_HASH EOF + ) echo "RELEASE_BODY<> $GITHUB_ENV echo "$RELEASE_BODY" >> $GITHUB_ENV From ba8a23c4ba2d22b3d5bcdc678e5a8095a56371de Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:38:10 +1100 Subject: [PATCH 027/180] docs: roadmap update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5eeaf9f..ba4a2f6 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Qopy is a fixed clipboard manager designed as a simple alternative to the standa - [ ] Metadata for copied items https://github.com/0PandaDEV/Qopy/issues/5 - [ ] Code highlighting https://github.com/0PandaDEV/Qopy/issues/7 - [ ] Streamshare integration https://github.com/0PandaDEV/Qopy/issues/4 +- [ ] Content type filter https://github.com/0PandaDEV/Qopy/issues/16 +- [ ] Preview for copied files https://github.com/0PandaDEV/Qopy/issues/15 - [x] Option for custom keybind https://github.com/0PandaDEV/Qopy/issues/3 - [x] macOS Support https://github.com/0PandaDEV/Qopy/issues/13 From 163b298783f4fa8c9d3d2c336dcea9bb1943d8ce Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:43:13 +1100 Subject: [PATCH 028/180] feat: create types This was commited on flight VA541 :) --- src-tauri/src/utils/types.rs | 23 +++++++++++++++++++++++ types/types.ts | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src-tauri/src/utils/types.rs create mode 100644 types/types.ts diff --git a/src-tauri/src/utils/types.rs b/src-tauri/src/utils/types.rs new file mode 100644 index 0000000..5b84d87 --- /dev/null +++ b/src-tauri/src/utils/types.rs @@ -0,0 +1,23 @@ +#[derive(Deserialize, Serialize)] +struct HistoryItem { + id: String, + content_type: ContentType, + content: String, + favicon: String, + timestamp: DATETIME, +} + +#[derive(Deserialize, Serialize)] +struct Settings { + key: String, + value: String, +} + +enum ContentType { + TEXT, + IMAGE, + FILE, + LINK, + COLOR, + CODE, +} diff --git a/types/types.ts b/types/types.ts new file mode 100644 index 0000000..f923c37 --- /dev/null +++ b/types/types.ts @@ -0,0 +1,21 @@ +export interface HistoryItem { + id: string; + content_type: ContentType; + content: string; + favicon: string; + timestamp: Date; +} + +export interface Settings { + key: string; + value: string; +} + +export enum ContentType { + TEXT, + IMAGE, + FILE, + LINK, + COLOR, + CODE, +} From 82ac6705912be0dc87722b2fa4a04b46607e7adc Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Mon, 9 Dec 2024 15:50:27 +1000 Subject: [PATCH 029/180] docs: add issue 17 to roadmap --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ba4a2f6..a39b815 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Qopy is a fixed clipboard manager designed as a simple alternative to the standa - [ ] Streamshare integration https://github.com/0PandaDEV/Qopy/issues/4 - [ ] Content type filter https://github.com/0PandaDEV/Qopy/issues/16 - [ ] Preview for copied files https://github.com/0PandaDEV/Qopy/issues/15 +- [ ] Convert files to other formats https://github.com/0PandaDEV/Qopy/issues/17 - [x] Option for custom keybind https://github.com/0PandaDEV/Qopy/issues/3 - [x] macOS Support https://github.com/0PandaDEV/Qopy/issues/13 From 7d15997dcba96f35451c0ca4d943d34e508ff34d Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:05:42 +1000 Subject: [PATCH 030/180] docs: add macos to setup guide --- GET_STARTED.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GET_STARTED.md b/GET_STARTED.md index 3807b7f..612ffbb 100644 --- a/GET_STARTED.md +++ b/GET_STARTED.md @@ -4,9 +4,10 @@ The hotkey for Qopy is Windows+V which is also the hotkey for the default clipbo All the data of Qopy is stored inside of a SQLite database. The location for the file differs for windows and linux. -| Operating System | Path | -|------------------|-------------------------------------------------------| -| Windows | `C:\Users\USERNAME\AppData\Roaming\net.pandadev.qopy` | +| Operating System | Path | +|------------------|-----------------------------------------------------------------| +| Windows | `C:\Users\USERNAME\AppData\Roaming\net.pandadev.qopy` | +| macOS | `/Users/USERNAME/Library/Application Support/net.pandadev.qopy` | | Linux | `` | ## Disable Windows+V for default clipboard manager From 4b3b6eaf21b5163e45356a4c1f2d5887e3f0eec3 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:50:46 +1000 Subject: [PATCH 031/180] Update FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index f72cd41..9904ddc 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ github: 0pandadev buy_me_a_coffee: pandadev_ +ko_fi: pandadev_ From a94496dbdbd353dd6c4b92a137fca9a07e798248 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:29:05 +1000 Subject: [PATCH 032/180] feat: move database access to rust --- pages/index.vue | 683 +++++++++++++++++++---------------- plugins/history.ts | 47 +++ plugins/settings.ts | 26 ++ src-tauri/src/db/history.rs | 148 ++++++++ src-tauri/src/db/settings.rs | 100 +++++ 5 files changed, 687 insertions(+), 317 deletions(-) create mode 100644 plugins/history.ts create mode 100644 plugins/settings.ts create mode 100644 src-tauri/src/db/history.rs create mode 100644 src-tauri/src/db/settings.rs diff --git a/pages/index.vue b/pages/index.vue index 559e557..57864aa 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,8 +1,21 @@ -
- Image +
+ Image
- YouTube Thumbnail +
+ YouTube Thumbnail +
{{ selectedItem?.content || "" }}
-
+
Information
-
+
+ +
+

Source

+ {{ selectedItem.source }} +
+
+

Content Type

+ {{ + selectedItem.content_type.charAt(0).toUpperCase() + + selectedItem.content_type.slice(1) + }} +
+ + + + + + + + + + + + + + + + + + + + +
+

Copied

+ {{ getFormattedDate }} +
+
+
@@ -121,10 +215,9 @@ interface GroupedHistory { items: HistoryItem[]; } -const { $history, $settings } = useNuxtApp(); +const { $history } = useNuxtApp(); const CHUNK_SIZE = 50; const SCROLL_THRESHOLD = 100; -const IMAGE_LOAD_DEBOUNCE = 300; const history = shallowRef([]); let offset = 0; @@ -141,6 +234,7 @@ const searchInput = ref(null); const os = ref(""); const imageUrls = shallowRef>({}); const imageDimensions = shallowRef>({}); +const imageSizes = shallowRef>({}); const lastUpdateTime = ref(Date.now()); const imageLoadError = ref(false); const imageLoading = ref(false); @@ -238,10 +332,34 @@ const loadHistoryChunk = async (): Promise => { }); if (historyItem.content_type === ContentType.Image) { - await Promise.all([ - getItemDimensions(historyItem), - loadImageUrl(historyItem), - ]); + try { + const base64 = await $history.readImage({ + filename: historyItem.content, + }); + const size = Math.ceil((base64.length * 3) / 4); + imageSizes.value[historyItem.id] = formatFileSize(size); + + const img = new Image(); + img.src = `data:image/png;base64,${base64}`; + imageUrls.value[historyItem.id] = img.src; + + await new Promise((resolve) => { + img.onload = () => { + imageDimensions.value[ + historyItem.id + ] = `${img.width}x${img.height}`; + resolve(); + }; + img.onerror = () => { + imageDimensions.value[historyItem.id] = "Error"; + resolve(); + }; + }); + } catch (error) { + console.error("Error processing image:", error); + imageDimensions.value[historyItem.id] = "Error"; + imageSizes.value[historyItem.id] = "Error"; + } } return historyItem; }) @@ -281,7 +399,7 @@ const scrollToSelectedItem = (forceScrollTop: boolean = false): void => { if (isAbove || isBelow) { const scrollOffset = isAbove - ? elementRect.top - viewportRect.top - 8 + ? elementRect.top - viewportRect.top - (selectedItemIndex.value === 0 ? 36 : 8) : elementRect.bottom - viewportRect.bottom + 9; viewport.scrollBy({ top: scrollOffset, behavior: "smooth" }); @@ -347,7 +465,7 @@ const pasteSelectedItem = async (): Promise => { let contentType: string = selectedItem.value.content_type; if (contentType === "image") { try { - content = await $history.getImagePath(content); + content = await $history.readImage({ filename: content }); } catch (error) { console.error("Error reading image file:", error); return; @@ -394,65 +512,67 @@ const getFaviconFromDb = (favicon: string): string => { return `data:image/png;base64,${favicon}`; }; -const getImageData = async ( - item: HistoryItem -): Promise<{ url: string; dimensions: string }> => { - try { - const base64 = await $history.readImage({ filename: item.content }); - const dataUrl = `data:image/png;base64,${base64}`; - const img = new Image(); - img.src = dataUrl; - - await new Promise((resolve, reject) => { - img.onload = () => resolve(); - img.onerror = reject; - }); - - return { - url: dataUrl, - dimensions: `${img.width}x${img.height}`, - }; - } catch (error) { - console.error("Error processing image:", error); - return { url: "", dimensions: "Error" }; - } -}; - -const processHistoryItem = async (item: any): Promise => { - const historyItem = new HistoryItem( - item.content_type as string, - ContentType[item.content_type as keyof typeof ContentType], - item.content, - item.favicon - ); - - Object.assign(historyItem, { - id: item.id, - timestamp: new Date(item.timestamp), - }); - - if (historyItem.content_type === ContentType.Image) { - const { url, dimensions } = await getImageData(historyItem); - imageUrls.value[historyItem.id] = url; - imageDimensions.value[historyItem.id] = dimensions; - } - - return historyItem; -}; - const updateHistory = async (resetScroll: boolean = false): Promise => { - history.value = []; - offset = 0; - await loadHistoryChunk(); + const results = await $history.loadHistoryChunk(0, CHUNK_SIZE); + if (results.length > 0) { + const existingIds = new Set(history.value.map(item => item.id)); + const uniqueNewItems = results.filter(item => !existingIds.has(item.id)); + + const processedNewItems = await Promise.all( + uniqueNewItems.map(async (item) => { + const historyItem = new HistoryItem( + item.source, + item.content_type, + item.content, + item.favicon + ); + Object.assign(historyItem, { + id: item.id, + timestamp: new Date(item.timestamp), + }); - if ( - resetScroll && - resultsContainer.value?.osInstance()?.elements().viewport - ) { - resultsContainer.value.osInstance()?.elements().viewport?.scrollTo({ - top: 0, - behavior: "smooth", - }); + if (historyItem.content_type === ContentType.Image) { + try { + const base64 = await $history.readImage({ + filename: historyItem.content, + }); + const size = Math.ceil((base64.length * 3) / 4); + imageSizes.value[historyItem.id] = formatFileSize(size); + + const img = new Image(); + img.src = `data:image/png;base64,${base64}`; + imageUrls.value[historyItem.id] = img.src; + + await new Promise((resolve) => { + img.onload = () => { + imageDimensions.value[ + historyItem.id + ] = `${img.width}x${img.height}`; + resolve(); + }; + img.onerror = () => { + imageDimensions.value[historyItem.id] = "Error"; + resolve(); + }; + }); + } catch (error) { + console.error("Error processing image:", error); + imageDimensions.value[historyItem.id] = "Error"; + imageSizes.value[historyItem.id] = "Error"; + } + } + return historyItem; + }) + ); + + history.value = [...processedNewItems, ...history.value]; + + if (resetScroll && resultsContainer.value?.osInstance()?.elements().viewport) { + resultsContainer.value.osInstance()?.elements().viewport?.scrollTo({ + top: 0, + behavior: "smooth", + }); + } } }; @@ -466,29 +586,16 @@ const handleSelection = ( if (shouldScroll) scrollToSelectedItem(); }; -const handleMediaContent = async ( - content: string, - type: string -): Promise => { - if (type === "image") { - return await $history.getImagePath(content); - } - - if (isYoutubeWatchUrl(content)) { - const videoId = content.includes("youtu.be") - ? content.split("youtu.be/")[1] - : content.match(/[?&]v=([^&]+)/)?.[1]; - return videoId ? `https://img.youtube.com/vi/${videoId}/0.jpg` : ""; - } - - return content; -}; - const setupEventListeners = async (): Promise => { await listen("clipboard-content-updated", async () => { lastUpdateTime.value = Date.now(); - handleSelection(0, 0, false); await updateHistory(true); + if ( + groupedHistory.value.length > 0 && + groupedHistory.value[0].items.length > 0 + ) { + handleSelection(0, 0, false); + } }); await listen("tauri://focus", async () => { @@ -497,9 +604,7 @@ const setupEventListeners = async (): Promise => { const previousState = { groupIndex: selectedGroupIndex.value, itemIndex: selectedItemIndex.value, - scroll: - resultsContainer.value?.osInstance()?.elements().viewport - ?.scrollTop || 0, + scroll: resultsContainer.value?.osInstance()?.elements().viewport?.scrollTop || 0, }; await updateHistory(); @@ -507,9 +612,7 @@ const setupEventListeners = async (): Promise => { handleSelection(previousState.groupIndex, previousState.itemIndex, false); nextTick(() => { - const viewport = resultsContainer.value - ?.osInstance() - ?.elements().viewport; + const viewport = resultsContainer.value?.osInstance()?.elements().viewport; if (viewport) { viewport.scrollTo({ top: previousState.scroll, @@ -611,40 +714,38 @@ watch([selectedGroupIndex, selectedItemIndex], () => scrollToSelectedItem(false) ); -const getItemDimensions = async (item: HistoryItem) => { - if (!imageDimensions.value[item.id]) { - try { - const base64 = await $history.readImage({ filename: item.content }); - const img = new Image(); - img.src = `data:image/png;base64,${base64}`; - await new Promise((resolve, reject) => { - img.onload = () => resolve(); - img.onerror = () => reject(); - }); - imageDimensions.value[item.id] = `${img.width}x${img.height}`; - } catch (error) { - console.error("Error loading image dimensions:", error); - imageDimensions.value[item.id] = "Error"; - } - } - return imageDimensions.value[item.id] || "Loading..."; -}; - -const loadImageUrl = async (item: HistoryItem) => { - if (!imageUrls.value[item.id]) { - try { - const base64 = await $history.readImage({ filename: item.content }); - imageUrls.value[item.id] = `data:image/png;base64,${base64}`; - } catch (error) { - console.error("Error loading image:", error); - } - } -}; - const getComputedImageUrl = (item: HistoryItem | null): string => { if (!item) return ""; return imageUrls.value[item.id] || ""; }; + +const getCharacterCount = computed(() => { + return selectedItem.value?.content.length ?? 0; +}); + +const getWordCount = computed(() => { + return selectedItem.value?.content.trim().split(/\s+/).length ?? 0; +}); + +const getLineCount = computed(() => { + return selectedItem.value?.content.split("\n").length ?? 0; +}); + +const getFormattedDate = computed(() => { + if (!selectedItem.value?.timestamp) return ""; + return new Intl.DateTimeFormat("en-US", { + dateStyle: "medium", + timeStyle: "short", + }).format(selectedItem.value.timestamp); +}); + +const formatFileSize = (bytes: number): string => { + if (bytes === 0) return "0 Bytes"; + const k = 1024; + const sizes = ["Bytes", "KB", "MB", "GB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; +}; \ No newline at end of file +@use "~/assets/css/settings.scss"; + diff --git a/plugins/history.ts b/plugins/history.ts index dd880b0..934ded5 100644 --- a/plugins/history.ts +++ b/plugins/history.ts @@ -27,8 +27,12 @@ export default defineNuxtPlugin(() => { }); }, - async getImagePath(path: string): Promise { - return await invoke("get_image_path", { path }); + async deleteHistoryItem(id: string): Promise { + await invoke("delete_history_item", { id }); + }, + + async clearHistory(): Promise { + await invoke("clear_history"); }, async writeAndPaste(data: { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index a17efef..7293135 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -94,6 +94,15 @@ dependencies = [ "libc", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -110,6 +119,31 @@ dependencies = [ "objc", ] +[[package]] +name = "applications" +version = "0.2.3" +source = "git+https://github.com/HuakunShen/applications-rs?branch=dev#ac41b051f0ebeac96213c6c32621b098634219ac" +dependencies = [ + "anyhow", + "cocoa 0.25.0", + "core-foundation 0.9.4", + "glob", + "image", + "ini", + "lnk", + "objc", + "parselnk", + "plist", + "regex", + "serde", + "serde_derive", + "serde_json", + "tauri-icns", + "thiserror 1.0.63", + "walkdir", + "winreg 0.52.0", +] + [[package]] name = "arbitrary" version = "1.3.2" @@ -315,6 +349,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "auto-launch" version = "0.5.0" @@ -496,6 +541,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bstr" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "built" version = "0.7.4" @@ -675,6 +730,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "circular-queue" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34327ead1c743a10db339de35fb58957564b99d248a67985c55638b22c59b5" +dependencies = [ + "version_check", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -686,6 +750,21 @@ dependencies = [ "libloading 0.8.6", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "clipboard-rs" version = "0.2.1" @@ -725,6 +804,22 @@ dependencies = [ "objc", ] +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation 0.1.2", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "foreign-types 0.5.0", + "libc", + "objc", +] + [[package]] name = "cocoa" version = "0.26.0" @@ -733,7 +828,7 @@ checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" dependencies = [ "bitflags 2.6.0", "block", - "cocoa-foundation", + "cocoa-foundation 0.2.0", "core-foundation 0.10.0", "core-graphics 0.24.0", "foreign-types 0.5.0", @@ -741,6 +836,20 @@ dependencies = [ "objc", ] +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "libc", + "objc", +] + [[package]] name = "cocoa-foundation" version = "0.2.0" @@ -780,6 +889,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "configparser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe1d7dcda7d1da79e444bdfba1465f2f849a58b07774e1df473ee77030cb47a7" + [[package]] name = "const-oid" version = "0.9.6" @@ -1065,7 +1180,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.87", ] @@ -1931,6 +2046,19 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "globset" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + [[package]] name = "gobject-sys" version = "0.18.0" @@ -2060,6 +2188,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.9" @@ -2233,6 +2370,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperpolyglot" +version = "0.1.7" +source = "git+https://github.com/0pandadev/hyperpolyglot#f4f463d7430d870568584ffd55c901f4576a6bae" +dependencies = [ + "clap", + "ignore", + "lazy_static", + "num_cpus", + "pcre2", + "phf 0.11.2", + "phf_codegen 0.11.2", + "polyglot_tokenizer", + "regex", + "serde", + "serde_yaml", + "termcolor", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -2411,6 +2567,22 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "image" version = "0.25.5" @@ -2500,6 +2672,15 @@ dependencies = [ "cfb", ] +[[package]] +name = "ini" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a9271a5dfd4228fa56a78d7508a35c321639cc71f783bb7a5723552add87bce" +dependencies = [ + "configparser", +] + [[package]] name = "instant" version = "0.1.13" @@ -2781,6 +2962,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -2793,6 +2980,20 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +[[package]] +name = "lnk" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e066ce29d4da51727b57c404c1270e3fa2a5ded0db1a4cb67c61f7a132421b2c" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "chrono", + "log", + "num-derive 0.3.3", + "num-traits", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -3068,6 +3269,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-derive" version = "0.4.2" @@ -3120,6 +3332,16 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -3509,12 +3731,47 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "parselnk" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0088616e6efe53ab79907b9313f4743eb3f8a16eb1e0014af810164808906dc3" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "chrono", + "thiserror 1.0.63", + "widestring", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pcre2" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be55c43ac18044541d58d897e8f4c55157218428953ebd39d86df3ba0286b2b" +dependencies = [ + "libc", + "log", + "pcre2-sys", +] + +[[package]] +name = "pcre2-sys" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "550f5d18fb1b90c20b87e161852c10cde77858c3900c5059b5ad2a1449f11d8a" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -3586,6 +3843,16 @@ dependencies = [ "phf_shared 0.10.0", ] +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", +] + [[package]] name = "phf_generator" version = "0.8.0" @@ -3781,6 +4048,14 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "polyglot_tokenizer" +version = "0.2.1" +source = "git+https://github.com/0pandadev/hyperpolyglot#f4f463d7430d870568584ffd55c901f4576a6bae" +dependencies = [ + "circular-queue", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3904,9 +4179,11 @@ name = "qopy" version = "0.2.1" dependencies = [ "active-win-pos-rs", + "applications", "base64 0.22.1", "chrono", "global-hotkey", + "hyperpolyglot", "image", "include_dir", "lazy_static", @@ -4127,7 +4404,7 @@ dependencies = [ "maybe-rayon", "new_debug_unreachable", "noop_proc_macro", - "num-derive", + "num-derive 0.4.2", "num-traits", "once_cell", "paste", @@ -4689,6 +4966,18 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap 1.9.3", + "ryu", + "serde", + "yaml-rust", +] + [[package]] name = "serialize-to-javascript" version = "0.1.1" @@ -5147,6 +5436,12 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.11.1" @@ -5444,6 +5739,16 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-icns" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b7eb4d0d43724ba9ba6a6717420ee68aee377816a3edbb45db8c18862b1431" +dependencies = [ + "byteorder", + "png", +] + [[package]] name = "tauri-macros" version = "2.0.3" @@ -5580,9 +5885,9 @@ dependencies = [ [[package]] name = "tauri-plugin-prevent-default" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d16274f883d2810fa8357124361656074599f5f9b52c8dff381ad82491b8a43" +checksum = "ce34a821424cdb5c74b390ddc8f08774d836030c07ab8dd35bd180690ef1331e" dependencies = [ "bitflags 2.6.0", "itertools 0.13.0", @@ -5758,6 +6063,24 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thin-slice" version = "0.1.1" @@ -6188,6 +6511,12 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -6269,6 +6598,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version-compare" version = "0.2.0" @@ -6604,6 +6939,12 @@ dependencies = [ "wasite", ] +[[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + [[package]] name = "winapi" version = "0.3.9" @@ -7127,6 +7468,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yoke" version = "0.7.4" diff --git a/src-tauri/src/api/hotkeys.rs b/src-tauri/src/api/hotkeys.rs index f35d9c8..7a0b015 100644 --- a/src-tauri/src/api/hotkeys.rs +++ b/src-tauri/src/api/hotkeys.rs @@ -3,9 +3,9 @@ use global_hotkey::{ hotkey::{Code, HotKey, Modifiers}, GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState, }; -use std::str::FromStr; use std::cell::RefCell; -use tauri::{AppHandle, Manager, Listener}; +use std::str::FromStr; +use tauri::{AppHandle, Listener, Manager}; thread_local! { static HOTKEY_MANAGER: RefCell> = RefCell::new(None); @@ -18,20 +18,21 @@ pub fn setup(app_handle: tauri::AppHandle) { HOTKEY_MANAGER.with(|m| *m.borrow_mut() = Some(manager)); let rt = app_handle.state::(); - let initial_keybind = rt.block_on(crate::db::settings::get_keybind(app_handle_clone.clone())) + let initial_keybind = rt + .block_on(crate::db::settings::get_keybind(app_handle_clone.clone())) .expect("Failed to get initial keybind"); let initial_shortcut = initial_keybind.join("+"); - + let initial_shortcut_for_update = initial_shortcut.clone(); let initial_shortcut_for_save = initial_shortcut.clone(); - + if let Err(e) = register_shortcut(&initial_shortcut) { eprintln!("Error registering initial shortcut: {:?}", e); } app_handle.listen("update-shortcut", move |event| { let payload_str = event.payload().to_string(); - + if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_update) { HOTKEY_MANAGER.with(|manager| { if let Some(manager) = manager.borrow().as_ref() { @@ -47,7 +48,7 @@ pub fn setup(app_handle: tauri::AppHandle) { app_handle.listen("save_keybind", move |event| { let payload_str = event.payload().to_string(); - + if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_save) { HOTKEY_MANAGER.with(|manager| { if let Some(manager) = manager.borrow().as_ref() { @@ -110,14 +111,17 @@ fn parse_hotkey(shortcut: &str) -> Result> { } else { key.to_string() }; - - code = Some(Code::from_str(&key_code) - .map_err(|_| format!("Invalid key code: {}", key_code))?); + + code = Some( + Code::from_str(&key_code) + .map_err(|_| format!("Invalid key code: {}", key_code))?, + ); } } } - let key_code = code.ok_or_else(|| format!("No valid key code found in shortcut: {}", shortcut))?; + let key_code = + code.ok_or_else(|| format!("No valid key code found in shortcut: {}", shortcut))?; Ok(HotKey::new(Some(modifiers), key_code)) } diff --git a/src-tauri/src/api/mod.rs b/src-tauri/src/api/mod.rs index e6643f9..e3f7afa 100644 --- a/src-tauri/src/api/mod.rs +++ b/src-tauri/src/api/mod.rs @@ -1,4 +1,4 @@ -pub mod updater; pub mod clipboard; -pub mod tray; pub mod hotkeys; +pub mod tray; +pub mod updater; diff --git a/src-tauri/src/api/tray.rs b/src-tauri/src/api/tray.rs index 6b78b8c..82dd843 100644 --- a/src-tauri/src/api/tray.rs +++ b/src-tauri/src/api/tray.rs @@ -1,5 +1,7 @@ use tauri::{ - menu::{MenuBuilder, MenuItemBuilder}, tray::TrayIconBuilder, Emitter, Manager + menu::{MenuBuilder, MenuItemBuilder}, + tray::TrayIconBuilder, + Emitter, Manager, }; pub fn setup(app: &mut tauri::App) -> Result<(), Box> { diff --git a/src-tauri/src/api/updater.rs b/src-tauri/src/api/updater.rs index b5d1b3c..a5e16f9 100644 --- a/src-tauri/src/api/updater.rs +++ b/src-tauri/src/api/updater.rs @@ -1,5 +1,5 @@ -use tauri::{AppHandle, async_runtime}; -use tauri_plugin_dialog::{DialogExt, MessageDialogKind, MessageDialogButtons}; +use tauri::{async_runtime, AppHandle}; +use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind}; use tauri_plugin_updater::UpdaterExt; pub async fn check_for_updates(app: AppHandle) { diff --git a/src-tauri/src/db/database.rs b/src-tauri/src/db/database.rs index 30867c5..4a3468d 100644 --- a/src-tauri/src/db/database.rs +++ b/src-tauri/src/db/database.rs @@ -1,8 +1,8 @@ +use include_dir::{include_dir, Dir}; use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; use std::fs; use tauri::Manager; use tokio::runtime::Runtime as TokioRuntime; -use include_dir::{include_dir, Dir}; static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/src/db/migrations"); @@ -49,39 +49,32 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box> { } async fn apply_migrations(pool: &SqlitePool) -> Result<(), Box> { - println!("Starting migration process"); - - // Create schema_version table sqlx::query( "CREATE TABLE IF NOT EXISTS schema_version ( version INTEGER PRIMARY KEY, applied_at DATETIME DEFAULT CURRENT_TIMESTAMP - );" + );", ) .execute(pool) .await?; - let current_version: Option = sqlx::query_scalar( - "SELECT MAX(version) FROM schema_version" - ) - .fetch_one(pool) - .await?; + let current_version: Option = + sqlx::query_scalar("SELECT MAX(version) FROM schema_version") + .fetch_one(pool) + .await?; let current_version = current_version.unwrap_or(0); - println!("Current database version: {}", current_version); let mut migration_files: Vec<(i64, &str)> = MIGRATIONS_DIR .files() .filter_map(|file| { let file_name = file.path().file_name()?.to_str()?; - println!("Processing file: {}", file_name); if file_name.ends_with(".sql") && file_name.starts_with("migration") { let version: i64 = file_name .trim_start_matches("migration") .trim_end_matches(".sql") .parse() .ok()?; - println!("Found migration version: {}", version); Some((version, file.contents_utf8()?)) } else { None @@ -93,8 +86,6 @@ async fn apply_migrations(pool: &SqlitePool) -> Result<(), Box current_version { - println!("Applying migration {}", version); - let statements: Vec<&str> = content .split(';') .map(|s| s.trim()) @@ -102,7 +93,6 @@ async fn apply_migrations(pool: &SqlitePool) -> Result<(), Box Result<(), Box, - key: String + key: String, ) -> Result { let row = sqlx::query("SELECT value FROM settings WHERE key = ?") .bind(key) @@ -65,7 +63,7 @@ pub async fn get_setting( pub async fn save_setting( pool: tauri::State<'_, SqlitePool>, key: String, - value: String + value: String, ) -> Result<(), String> { sqlx::query("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)") .bind(key) @@ -78,23 +76,18 @@ pub async fn save_setting( } #[tauri::command] -pub async fn get_keybind( - app_handle: tauri::AppHandle, -) -> Result, String> { +pub async fn get_keybind(app_handle: tauri::AppHandle) -> Result, String> { let pool = app_handle.state::(); - + let row = sqlx::query("SELECT value FROM settings WHERE key = 'keybind'") .fetch_optional(&*pool) .await .map_err(|e| e.to_string())?; - let json = row - .map(|r| r.get::("value")) - .unwrap_or_else(|| { - serde_json::to_string(&vec!["Meta".to_string(), "V".to_string()]) - .expect("Failed to serialize default keybind") - }); + let json = row.map(|r| r.get::("value")).unwrap_or_else(|| { + serde_json::to_string(&vec!["Meta".to_string(), "V".to_string()]) + .expect("Failed to serialize default keybind") + }); - serde_json::from_str::>(&json) - .map_err(|e| e.to_string()) -} \ No newline at end of file + serde_json::from_str::>(&json).map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/utils/favicon.rs b/src-tauri/src/utils/favicon.rs index 0091313..38321f3 100644 --- a/src-tauri/src/utils/favicon.rs +++ b/src-tauri/src/utils/favicon.rs @@ -4,7 +4,9 @@ use image::ImageFormat; use reqwest; use url::Url; -pub async fn fetch_favicon_as_base64(url: Url) -> Result, Box> { +pub async fn fetch_favicon_as_base64( + url: Url, +) -> Result, Box> { let client = reqwest::Client::new(); let favicon_url = format!("https://favicone.com/{}", url.host_str().unwrap()); let response = client.get(&favicon_url).send().await?; @@ -18,4 +20,4 @@ pub async fn fetch_favicon_as_base64(url: Url) -> Result, Box Date: Mon, 16 Dec 2024 23:53:29 +1000 Subject: [PATCH 052/180] feat: add logging for debugging --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 1 + src-tauri/src/main.rs | 2 ++ src-tauri/src/utils/logger.rs | 49 +++++++++++++++++++++++++++++++++++ src-tauri/src/utils/mod.rs | 1 + 5 files changed, 54 insertions(+) create mode 100644 src-tauri/src/utils/logger.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 7293135..a05f2b9 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4187,6 +4187,7 @@ dependencies = [ "image", "include_dir", "lazy_static", + "log", "rand 0.8.5", "rdev", "regex", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ce4353d..fc33f12 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -40,6 +40,7 @@ lazy_static = "1.5.0" time = "0.3.37" global-hotkey = "0.6.3" chrono = { version = "0.4.39", features = ["serde"] } +log = { version = "0.4.22", features = ["std"] } uuid = "1.11.0" active-win-pos-rs = "0.8.3" include_dir = "0.7.4" diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 36a3072..26d1048 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -34,6 +34,8 @@ fn main() { ) .setup(|app| { let app_data_dir = app.path().app_data_dir().unwrap(); + utils::logger::init_logger(&app_data_dir).expect("Failed to initialize logger"); + fs::create_dir_all(&app_data_dir).expect("Failed to create app data directory"); let db_path = app_data_dir.join("data.db"); diff --git a/src-tauri/src/utils/logger.rs b/src-tauri/src/utils/logger.rs new file mode 100644 index 0000000..d2f1442 --- /dev/null +++ b/src-tauri/src/utils/logger.rs @@ -0,0 +1,49 @@ +use chrono; +use log::{LevelFilter, SetLoggerError}; +use std::fs::{File, OpenOptions}; +use std::io::Write; + +pub struct FileLogger { + file: File, +} + +impl log::Log for FileLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if self.enabled(record.metadata()) { + let mut file = self.file.try_clone().expect("Failed to clone file handle"); + writeln!( + file, + "{} - {}: {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), + record.level(), + record.args() + ) + .expect("Failed to write to log file"); + } + } + + fn flush(&self) { + self.file.sync_all().expect("Failed to flush log file"); + } +} + +pub fn init_logger(app_data_dir: &std::path::Path) -> Result<(), SetLoggerError> { + let logs_dir = app_data_dir.join("logs"); + std::fs::create_dir_all(&logs_dir).expect("Failed to create logs directory"); + + let log_path = logs_dir.join("app.log"); + let file = OpenOptions::new() + .create(true) + .append(true) + .open(log_path) + .expect("Failed to open log file"); + + let logger = Box::new(FileLogger { file }); + unsafe { log::set_logger_racy(Box::leak(logger))? }; + log::set_max_level(LevelFilter::Debug); + Ok(()) +} diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index 5ff2fca..b888b1f 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -1,3 +1,4 @@ pub mod commands; pub mod favicon; pub mod types; +pub mod logger; From 345f7e3f09bc12f30072852406a6a71b6f8c86d2 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:00:21 +1000 Subject: [PATCH 053/180] fix: youtube thumbnail having strange formats --- assets/css/index.scss | 19 +------------------ pages/index.vue | 44 ++++++++++++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/assets/css/index.scss b/assets/css/index.scss index 33d4af9..43fe481 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -111,7 +111,7 @@ $mutedtext: #78756f; align-items: center; overflow: hidden; - &:not(:has(.full-image, .image)) { + &:not(:has(.image)) { padding: 8px; } @@ -119,23 +119,6 @@ $mutedtext: #78756f; font-family: CommitMono Nerd Font !important; } - .full-image { - width: 100%; - height: 100%; - position: relative; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - - img { - width: 100%; - height: 100%; - object-fit: contain; - object-position: center; - } - } - .image { width: 100%; height: 100%; diff --git a/pages/index.vue b/pages/index.vue index c218720..4d7be6a 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -87,19 +87,24 @@
+
Image
+
+ YouTube Thumbnail +
-
- YouTube Thumbnail -
- {{ selectedItem?.content || "" }} + {{ selectedItem?.content || "" }}
+ @@ -399,7 +404,9 @@ const scrollToSelectedItem = (forceScrollTop: boolean = false): void => { if (isAbove || isBelow) { const scrollOffset = isAbove - ? elementRect.top - viewportRect.top - (selectedItemIndex.value === 0 ? 36 : 8) + ? elementRect.top - + viewportRect.top - + (selectedItemIndex.value === 0 ? 36 : 8) : elementRect.bottom - viewportRect.bottom + 9; viewport.scrollBy({ top: scrollOffset, behavior: "smooth" }); @@ -504,8 +511,8 @@ const getYoutubeThumbnail = (url: string): string => { videoId = url.match(/[?&]v=([^&]+)/)?.[1]; } return videoId - ? `https://img.youtube.com/vi/${videoId}/0.jpg` - : "https://via.placeholder.com/150"; + ? `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg` + : "https://via.placeholder.com/1280x720"; }; const getFaviconFromDb = (favicon: string): string => { @@ -515,9 +522,9 @@ const getFaviconFromDb = (favicon: string): string => { const updateHistory = async (resetScroll: boolean = false): Promise => { const results = await $history.loadHistoryChunk(0, CHUNK_SIZE); if (results.length > 0) { - const existingIds = new Set(history.value.map(item => item.id)); - const uniqueNewItems = results.filter(item => !existingIds.has(item.id)); - + const existingIds = new Set(history.value.map((item) => item.id)); + const uniqueNewItems = results.filter((item) => !existingIds.has(item.id)); + const processedNewItems = await Promise.all( uniqueNewItems.map(async (item) => { const historyItem = new HistoryItem( @@ -567,7 +574,10 @@ const updateHistory = async (resetScroll: boolean = false): Promise => { history.value = [...processedNewItems, ...history.value]; - if (resetScroll && resultsContainer.value?.osInstance()?.elements().viewport) { + if ( + resetScroll && + resultsContainer.value?.osInstance()?.elements().viewport + ) { resultsContainer.value.osInstance()?.elements().viewport?.scrollTo({ top: 0, behavior: "smooth", @@ -604,7 +614,9 @@ const setupEventListeners = async (): Promise => { const previousState = { groupIndex: selectedGroupIndex.value, itemIndex: selectedItemIndex.value, - scroll: resultsContainer.value?.osInstance()?.elements().viewport?.scrollTop || 0, + scroll: + resultsContainer.value?.osInstance()?.elements().viewport + ?.scrollTop || 0, }; await updateHistory(); @@ -612,7 +624,9 @@ const setupEventListeners = async (): Promise => { handleSelection(previousState.groupIndex, previousState.itemIndex, false); nextTick(() => { - const viewport = resultsContainer.value?.osInstance()?.elements().viewport; + const viewport = resultsContainer.value + ?.osInstance() + ?.elements().viewport; if (viewport) { viewport.scrollTo({ top: previousState.scroll, From 4ab938a3de060e4aa0a29cb2fd082d2f639af70c Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:15:20 +1000 Subject: [PATCH 054/180] feat: detect color --- pages/index.vue | 102 +++++++++++++++++++++++--------- src-tauri/src/api/clipboard.rs | 5 ++ src-tauri/src/utils/commands.rs | 46 ++++++++++++++ 3 files changed, 126 insertions(+), 27 deletions(-) diff --git a/pages/index.vue b/pages/index.vue index 4d7be6a..0426d08 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -63,11 +63,13 @@ @error="onImageError" /> - Favicon + +
+ + + + + + + +
@@ -600,10 +656,7 @@ const setupEventListeners = async (): Promise => { await listen("clipboard-content-updated", async () => { lastUpdateTime.value = Date.now(); await updateHistory(true); - if ( - groupedHistory.value.length > 0 && - groupedHistory.value[0].items.length > 0 - ) { + if (groupedHistory.value[0]?.items.length > 0) { handleSelection(0, 0, false); } }); @@ -623,17 +676,12 @@ const setupEventListeners = async (): Promise => { lastUpdateTime.value = currentTime; handleSelection(previousState.groupIndex, previousState.itemIndex, false); - nextTick(() => { - const viewport = resultsContainer.value - ?.osInstance() - ?.elements().viewport; - if (viewport) { - viewport.scrollTo({ - top: previousState.scroll, - behavior: "instant", - }); - } - }); + if (resultsContainer.value?.osInstance()?.elements().viewport?.scrollTo) { + resultsContainer.value.osInstance()?.elements().viewport?.scrollTo({ + top: previousState.scroll, + behavior: "instant", + }); + } } focusSearchInput(); }); @@ -749,7 +797,7 @@ const getFormattedDate = computed(() => { if (!selectedItem.value?.timestamp) return ""; return new Intl.DateTimeFormat("en-US", { dateStyle: "medium", - timeStyle: "short", + timeStyle: "medium", }).format(selectedItem.value.timestamp); }); diff --git a/src-tauri/src/api/clipboard.rs b/src-tauri/src/api/clipboard.rs index 927b70e..405ee12 100644 --- a/src-tauri/src/api/clipboard.rs +++ b/src-tauri/src/api/clipboard.rs @@ -164,6 +164,11 @@ pub fn setup(app: &AppHandle) { pool, HistoryItem::new(app_name, ContentType::Code, text, None, app_icon, Some(language)) ).await; + } else if crate::utils::commands::detect_color(&text) { + let _ = db::history::add_history_item( + pool, + HistoryItem::new(app_name, ContentType::Color, text, None, app_icon, None) + ).await; } else { let _ = db::history::add_history_item( pool, diff --git a/src-tauri/src/utils/commands.rs b/src-tauri/src/utils/commands.rs index 13a5d04..6ffa6c9 100644 --- a/src-tauri/src/utils/commands.rs +++ b/src-tauri/src/utils/commands.rs @@ -49,3 +49,49 @@ fn _process_icon_to_base64(path: &str) -> Result bool { + let color = color.trim().to_lowercase(); + + // hex + if color.starts_with('#') && color.len() == color.trim_end_matches(char::is_whitespace).len() { + let hex = &color[1..]; + return match hex.len() { + 3 | 6 | 8 => hex.chars().all(|c| c.is_ascii_hexdigit()), + _ => false + }; + } + + // rgb/rgba + if (color.starts_with("rgb(") || color.starts_with("rgba(")) && color.ends_with(")") && !color[..color.len()-1].contains(")") { + let values = color + .trim_start_matches("rgba(") + .trim_start_matches("rgb(") + .trim_end_matches(')') + .split(',') + .collect::>(); + + return match values.len() { + 3 | 4 => values.iter().all(|v| v.trim().parse::().is_ok()), + _ => false + }; + } + + // hsl/hsla + if (color.starts_with("hsl(") || color.starts_with("hsla(")) && color.ends_with(")") && !color[..color.len()-1].contains(")") { + let values = color + .trim_start_matches("hsla(") + .trim_start_matches("hsl(") + .trim_end_matches(')') + .split(',') + .collect::>(); + + return match values.len() { + 3 | 4 => values.iter().all(|v| v.trim().parse::().is_ok()), + _ => false + }; + } + + false +} \ No newline at end of file From 460888a1e72cd8373905e8e3ce98bd87e1b37147 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:15:34 +1000 Subject: [PATCH 055/180] feat: move item to the top if copied again --- src-tauri/src/db/history.rs | 57 +++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src-tauri/src/db/history.rs b/src-tauri/src/db/history.rs index 67895e5..fc24bcb 100644 --- a/src-tauri/src/db/history.rs +++ b/src-tauri/src/db/history.rs @@ -59,33 +59,42 @@ pub async fn add_history_item( let (id, source, source_icon, content_type, content, favicon, timestamp, language) = item.to_row(); - let last_content: Option = sqlx::query_scalar( - "SELECT content FROM history WHERE content_type = ? ORDER BY timestamp DESC LIMIT 1", - ) - .bind(content_type.clone()) - .fetch_one(&*pool) - .await - .unwrap_or(None); + let existing = sqlx::query("SELECT id FROM history WHERE content = ? AND content_type = ?") + .bind(&content) + .bind(&content_type) + .fetch_optional(&*pool) + .await + .map_err(|e| e.to_string())?; - if last_content.as_deref() == Some(&content) { - return Ok(()); + match existing { + Some(_) => { + sqlx::query( + "UPDATE history SET timestamp = strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now') WHERE content = ? AND content_type = ?" + ) + .bind(&content) + .bind(&content_type) + .execute(&*pool) + .await + .map_err(|e| e.to_string())?; + } + None => { + sqlx::query( + "INSERT INTO history (id, source, source_icon, content_type, content, favicon, timestamp, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" + ) + .bind(id) + .bind(source) + .bind(source_icon) + .bind(content_type) + .bind(content) + .bind(favicon) + .bind(timestamp) + .bind(language) + .execute(&*pool) + .await + .map_err(|e| e.to_string())?; + } } - sqlx::query( - "INSERT INTO history (id, source, source_icon, content_type, content, favicon, timestamp, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" - ) - .bind(id) - .bind(source) - .bind(source_icon) - .bind(content_type) - .bind(content) - .bind(favicon) - .bind(timestamp) - .bind(language) - .execute(&*pool) - .await - .map_err(|e| e.to_string())?; - Ok(()) } From ab57f1fa72131c3557a1b61bda85197ce1f08ca2 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:15:44 +1000 Subject: [PATCH 056/180] fix: icon inconsitencies --- assets/css/index.scss | 2 +- public/icons/Code.svg | 13 +++++-------- public/icons/File.svg | 13 +++++-------- public/icons/Link.svg | 7 +++++++ public/icons/Text.svg | 13 +++++-------- 5 files changed, 23 insertions(+), 25 deletions(-) create mode 100644 public/icons/Link.svg diff --git a/assets/css/index.scss b/assets/css/index.scss index 43fe481..da464c5 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -89,7 +89,7 @@ $mutedtext: #78756f; } .icon { - width: 20px; + width: 18px; height: 18px; } } diff --git a/public/icons/Code.svg b/public/icons/Code.svg index b5c1a42..5c34abf 100644 --- a/public/icons/Code.svg +++ b/public/icons/Code.svg @@ -1,10 +1,7 @@ - - - - + + + + + \ No newline at end of file diff --git a/public/icons/File.svg b/public/icons/File.svg index a0b4fdd..8341a3c 100644 --- a/public/icons/File.svg +++ b/public/icons/File.svg @@ -1,10 +1,7 @@ - - - - + + + + + \ No newline at end of file diff --git a/public/icons/Link.svg b/public/icons/Link.svg new file mode 100644 index 0000000..64cc120 --- /dev/null +++ b/public/icons/Link.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/public/icons/Text.svg b/public/icons/Text.svg index 83f8532..0ca21e8 100644 --- a/public/icons/Text.svg +++ b/public/icons/Text.svg @@ -1,10 +1,7 @@ - - - - + + + + + \ No newline at end of file From c42141f7c72112129b4078406cbd234addac947b Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:56:12 +1000 Subject: [PATCH 057/180] fix: overflow for urls --- assets/css/index.scss | 51 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/assets/css/index.scss b/assets/css/index.scss index da464c5..a013480 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -233,34 +233,39 @@ $mutedtext: #78756f; display: flex; gap: 0; flex-direction: column; - } - .info-row { - display: flex; - width: 100%; - font-size: 12px; - justify-content: space-between; - padding: 8px 0; - border-bottom: 1px solid $divider; + .info-row { + display: flex; + width: 100%; + font-size: 12px; + justify-content: space-between; + padding: 8px 0; + border-bottom: 1px solid $divider; - &:last-child { - border-bottom: none; - padding-bottom: 0; - } + &:last-child { + border-bottom: none; + padding-bottom: 0; + } - &:first-child { - padding-top: 22px; - } + &:first-child { + padding-top: 22px; + } - p { - font-family: SFRoundedMedium; - color: $text2; - font-weight: 500; - } + p { + font-family: SFRoundedMedium; + color: $text2; + font-weight: 500; + flex-shrink: 0; + } - span { - font-family: CommitMono; - color: $text; + span { + font-family: CommitMono; + color: $text; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin-left: 16px; + } } } } From 5943fc86fb8310ac4041d93432280a46f38c14d4 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:57:10 +1000 Subject: [PATCH 058/180] feat: better implementation of info rows --- pages/index.vue | 299 ++++++++++++++++++++--------------- src-tauri/src/utils/types.rs | 20 +-- types/types.ts | 21 +-- 3 files changed, 190 insertions(+), 150 deletions(-) diff --git a/pages/index.vue b/pages/index.vue index 0426d08..9c5b52e 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -129,130 +129,10 @@ class="information" :options="{ scrollbars: { autoHide: 'scroll' } }">
Information
-
- -
-

Source

- {{ selectedItem.source }} -
-
-

Content Type

- {{ - selectedItem.content_type.charAt(0).toUpperCase() + - selectedItem.content_type.slice(1) - }} -
- - - - - - - - - - - - - - - - - - - - -
-

Copied

- {{ getFormattedDate }} +
+
+

{{ row.label }}

+ {{ row.value }}
@@ -269,7 +149,9 @@ import { platform } from "@tauri-apps/plugin-os"; import { enable, isEnabled } from "@tauri-apps/plugin-autostart"; import { listen } from "@tauri-apps/api/event"; import { useNuxtApp } from "#app"; +import { invoke } from "@tauri-apps/api/core"; import { HistoryItem, ContentType } from "~/types/types"; +import type { InfoText, InfoImage, InfoFile, InfoLink, InfoColor, InfoCode } from "~/types/types"; interface GroupedHistory { label: string; @@ -299,6 +181,8 @@ const imageSizes = shallowRef>({}); const lastUpdateTime = ref(Date.now()); const imageLoadError = ref(false); const imageLoading = ref(false); +const pageTitle = ref(''); +const pageOgImage = ref(''); const keyboard = useKeyboard(); @@ -385,7 +269,9 @@ const loadHistoryChunk = async (): Promise => { item.source, item.content_type, item.content, - item.favicon + item.favicon, + item.source_icon, + item.language ); Object.assign(historyItem, { id: item.id, @@ -776,11 +662,6 @@ watch([selectedGroupIndex, selectedItemIndex], () => scrollToSelectedItem(false) ); -const getComputedImageUrl = (item: HistoryItem | null): string => { - if (!item) return ""; - return imageUrls.value[item.id] || ""; -}; - const getCharacterCount = computed(() => { return selectedItem.value?.content.length ?? 0; }); @@ -808,6 +689,164 @@ const formatFileSize = (bytes: number): string => { const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; }; + +const fetchPageMeta = async (url: string) => { + try { + console.log('Fetching metadata for:', url); + const [title, ogImage] = await invoke('fetch_page_meta', { url }) as [string, string | null]; + console.log('Received title:', title); + pageTitle.value = title; + if (ogImage) { + pageOgImage.value = ogImage; + } + } catch (error) { + console.error('Error fetching page meta:', error); + pageTitle.value = 'Error loading title'; + } +}; + +watch(() => selectedItem.value, (newItem) => { + if (newItem?.content_type === ContentType.Link) { + pageTitle.value = 'Loading...'; + pageOgImage.value = ''; + fetchPageMeta(newItem.content); + } else { + pageTitle.value = ''; + pageOgImage.value = ''; + } +}); + +const getInfo = computed(() => { + if (!selectedItem.value) return null; + + const baseInfo = { + source: selectedItem.value.source, + copied: selectedItem.value.timestamp, + }; + + const infoMap: Record InfoText | InfoImage | InfoFile | InfoLink | InfoColor | InfoCode> = { + [ContentType.Text]: () => ({ + ...baseInfo, + content_type: ContentType.Text, + characters: selectedItem.value!.content.length, + words: selectedItem.value!.content.trim().split(/\s+/).length, + }), + [ContentType.Image]: () => ({ + ...baseInfo, + content_type: ContentType.Image, + dimensions: imageDimensions.value[selectedItem.value!.id] || "Loading...", + size: parseInt(imageSizes.value[selectedItem.value!.id] || "0"), + }), + [ContentType.File]: () => ({ + ...baseInfo, + content_type: ContentType.File, + path: selectedItem.value!.content, + filesize: 0, + }), + [ContentType.Link]: () => ({ + ...baseInfo, + content_type: ContentType.Link, + title: pageTitle.value, + url: selectedItem.value!.content, + characters: selectedItem.value!.content.length, + }), + [ContentType.Color]: () => { + const hex = selectedItem.value!.content; + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + + const rNorm = r / 255; + const gNorm = g / 255; + const bNorm = b / 255; + + const max = Math.max(rNorm, gNorm, bNorm); + const min = Math.min(rNorm, gNorm, bNorm); + let h = 0, s = 0; + const l = (max + min) / 2; + + if (max !== min) { + const d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case rNorm: + h = (gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0); + break; + case gNorm: + h = (bNorm - rNorm) / d + 2; + break; + case bNorm: + h = (rNorm - gNorm) / d + 4; + break; + } + h /= 6; + } + + return { + ...baseInfo, + content_type: ContentType.Color, + hex: hex, + rgb: `rgb(${r}, ${g}, ${b})`, + hsl: `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`, + }; + }, + [ContentType.Code]: () => ({ + ...baseInfo, + content_type: ContentType.Code, + language: selectedItem.value!.language ?? "Unknown", + lines: selectedItem.value!.content.split('\n').length, + }), + }; + + return infoMap[selectedItem.value.content_type](); +}); + +const infoRows = computed(() => { + if (!getInfo.value) return []; + + const commonRows = [ + { label: "Source", value: getInfo.value.source }, + { label: "Content Type", value: getInfo.value.content_type.charAt(0).toUpperCase() + getInfo.value.content_type.slice(1) }, + ]; + + const typeSpecificRows: Record> = { + [ContentType.Text]: [ + { label: "Characters", value: (getInfo.value as InfoText).characters }, + { label: "Words", value: (getInfo.value as InfoText).words }, + ], + [ContentType.Image]: [ + { label: "Dimensions", value: (getInfo.value as InfoImage).dimensions }, + { label: "Image size", value: formatFileSize((getInfo.value as InfoImage).size) }, + ], + [ContentType.File]: [ + { label: "Path", value: (getInfo.value as InfoFile).path }, + ], + [ContentType.Link]: [ + { label: "Title", value: (getInfo.value as InfoLink).title || "No Title Found" }, + { label: "URL", value: (getInfo.value as InfoLink).url }, + { label: "Characters", value: (getInfo.value as InfoLink).characters }, + ], + [ContentType.Color]: [ + { label: "Hex Code", value: (getInfo.value as InfoColor).hex }, + { label: "RGB", value: (getInfo.value as InfoColor).rgb }, + { label: "HSL", value: (getInfo.value as InfoColor).hsl }, + ], + [ContentType.Code]: [ + { label: "Language", value: (getInfo.value as InfoCode).language }, + { label: "Lines", value: (getInfo.value as InfoCode).lines }, + ], + }; + + const specificRows = typeSpecificRows[getInfo.value.content_type] + .filter(row => row.value !== ""); + + return [ + ...commonRows, + ...specificRows, + { label: "Copied", value: getFormattedDate.value }, + ]; +}); \ No newline at end of file + diff --git a/pages/index.vue b/pages/index.vue index c902e9b..50a57c3 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -65,10 +65,17 @@ YouTube Thumbnail
-
- Image +
+ Image
{{ selectedItem?.content || "" }} @@ -135,9 +146,7 @@

{{ row.label }}

- + {{ row.value }}
@@ -158,7 +167,15 @@ import { listen } from "@tauri-apps/api/event"; import { useNuxtApp } from "#app"; import { invoke } from "@tauri-apps/api/core"; import { HistoryItem, ContentType } from "~/types/types"; -import type { InfoText, InfoImage, InfoFile, InfoLink, InfoColor, InfoCode } from "~/types/types"; +import type { + InfoText, + InfoImage, + InfoFile, + InfoLink, + InfoColor, + InfoCode, +} from "~/types/types"; +import { Key } from "wrdu-keyboard/key"; interface GroupedHistory { label: string; @@ -188,8 +205,8 @@ const imageSizes = shallowRef>({}); const lastUpdateTime = ref(Date.now()); const imageLoadError = ref(false); const imageLoading = ref(false); -const pageTitle = ref(''); -const pageOgImage = ref(''); +const pageTitle = ref(""); +const pageOgImage = ref(""); const keyboard = useKeyboard(); @@ -583,41 +600,35 @@ const setupEventListeners = async (): Promise => { searchInput.value?.blur(); }); - keyboard.down("ArrowDown", (event) => { - event.preventDefault(); + keyboard.prevent.down([Key.DownArrow], (event) => { selectNext(); }); - keyboard.down("ArrowUp", (event) => { - event.preventDefault(); + keyboard.prevent.down([Key.UpArrow], (event) => { selectPrevious(); }); - keyboard.down("Enter", (event) => { - event.preventDefault(); + keyboard.prevent.down([Key.Enter], (event) => { pasteSelectedItem(); }); - keyboard.down("Escape", (event) => { - event.preventDefault(); + keyboard.prevent.down([Key.Escape], (event) => { hideApp(); }); - keyboard.down("all", (event) => { - const isMacActionCombo = - os.value === "macos" && - (event.code === "MetaLeft" || event.code === "MetaRight") && - event.key === "k"; + switch (os.value) { + case "macos": + keyboard.prevent.down([Key.LeftMeta, Key.K], (event) => {}); - const isOtherOsActionCombo = - os.value !== "macos" && - (event.code === "ControlLeft" || event.code === "ControlRight") && - event.key === "k"; + keyboard.prevent.down([Key.RightMeta, Key.K], (event) => {}); + break; - if (isMacActionCombo || isOtherOsActionCombo) { - event.preventDefault(); - } - }); + case "linux" || "windows": + keyboard.prevent.down([Key.LeftControl, Key.K], (event) => {}); + + keyboard.prevent.down([Key.RightControl, Key.K], (event) => {}); + break; + } }; const hideApp = async (): Promise => { @@ -646,7 +657,7 @@ watch(searchQuery, () => { onMounted(async () => { try { - os.value = await platform(); + os.value = platform(); await loadHistoryChunk(); resultsContainer.value @@ -686,27 +697,33 @@ const formatFileSize = (bytes: number): string => { const fetchPageMeta = async (url: string) => { try { - const [title, ogImage] = await invoke('fetch_page_meta', { url }) as [string, string | null]; + const [title, ogImage] = (await invoke("fetch_page_meta", { url })) as [ + string, + string | null + ]; pageTitle.value = title; if (ogImage) { pageOgImage.value = ogImage; } } catch (error) { - console.error('Error fetching page meta:', error); - pageTitle.value = 'Error loading title'; + console.error("Error fetching page meta:", error); + pageTitle.value = "Error loading title"; } }; -watch(() => selectedItem.value, (newItem) => { - if (newItem?.content_type === ContentType.Link) { - pageTitle.value = 'Loading...'; - pageOgImage.value = ''; - fetchPageMeta(newItem.content); - } else { - pageTitle.value = ''; - pageOgImage.value = ''; +watch( + () => selectedItem.value, + (newItem) => { + if (newItem?.content_type === ContentType.Link) { + pageTitle.value = "Loading..."; + pageOgImage.value = ""; + fetchPageMeta(newItem.content); + } else { + pageTitle.value = ""; + pageOgImage.value = ""; + } } -}); +); const getInfo = computed(() => { if (!selectedItem.value) return null; @@ -716,7 +733,10 @@ const getInfo = computed(() => { copied: selectedItem.value.timestamp, }; - const infoMap: Record InfoText | InfoImage | InfoFile | InfoLink | InfoColor | InfoCode> = { + const infoMap: Record< + ContentType, + () => InfoText | InfoImage | InfoFile | InfoLink | InfoColor | InfoCode + > = { [ContentType.Text]: () => ({ ...baseInfo, content_type: ContentType.Text, @@ -747,20 +767,21 @@ const getInfo = computed(() => { const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); - + const rNorm = r / 255; const gNorm = g / 255; const bNorm = b / 255; - + const max = Math.max(rNorm, gNorm, bNorm); const min = Math.min(rNorm, gNorm, bNorm); - let h = 0, s = 0; + let h = 0, + s = 0; const l = (max + min) / 2; if (max !== min) { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - + switch (max) { case rNorm: h = (gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0); @@ -780,14 +801,16 @@ const getInfo = computed(() => { content_type: ContentType.Color, hex: hex, rgb: `rgb(${r}, ${g}, ${b})`, - hsl: `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`, + hsl: `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round( + l * 100 + )}%)`, }; }, [ContentType.Code]: () => ({ ...baseInfo, content_type: ContentType.Code, language: selectedItem.value!.language ?? "Unknown", - lines: selectedItem.value!.content.split('\n').length, + lines: selectedItem.value!.content.split("\n").length, }), }; @@ -799,24 +822,37 @@ const infoRows = computed(() => { const commonRows = [ { label: "Source", value: getInfo.value.source, isUrl: false }, - { label: "Content Type", value: getInfo.value.content_type.charAt(0).toUpperCase() + getInfo.value.content_type.slice(1), isUrl: false }, + { + label: "Content Type", + value: + getInfo.value.content_type.charAt(0).toUpperCase() + + getInfo.value.content_type.slice(1), + isUrl: false, + }, ]; - const typeSpecificRows: Record> = { + const typeSpecificRows: Record< + ContentType, + Array<{ label: string; value: string | number; isUrl?: boolean }> + > = { [ContentType.Text]: [ { label: "Characters", value: (getInfo.value as InfoText).characters }, { label: "Words", value: (getInfo.value as InfoText).words }, ], [ContentType.Image]: [ { label: "Dimensions", value: (getInfo.value as InfoImage).dimensions }, - { label: "Image size", value: formatFileSize((getInfo.value as InfoImage).size) }, + { + label: "Image size", + value: formatFileSize((getInfo.value as InfoImage).size), + }, ], [ContentType.File]: [ { label: "Path", value: (getInfo.value as InfoFile).path }, ], [ContentType.Link]: [ - ...((getInfo.value as InfoLink).title && (getInfo.value as InfoLink).title !== 'Loading...' - ? [{ label: "Title", value: (getInfo.value as InfoLink).title || '' }] + ...((getInfo.value as InfoLink).title && + (getInfo.value as InfoLink).title !== "Loading..." + ? [{ label: "Title", value: (getInfo.value as InfoLink).title || "" }] : []), { label: "URL", value: (getInfo.value as InfoLink).url, isUrl: true }, { label: "Characters", value: (getInfo.value as InfoLink).characters }, @@ -832,8 +868,9 @@ const infoRows = computed(() => { ], }; - const specificRows = typeSpecificRows[getInfo.value.content_type] - .filter(row => row.value !== ""); + const specificRows = typeSpecificRows[getInfo.value.content_type].filter( + (row) => row.value !== "" + ); return [ ...commonRows, diff --git a/patches/wrdu-keyboard@3.0.0.patch b/patches/wrdu-keyboard@3.0.0.patch new file mode 100644 index 0000000..e973647 --- /dev/null +++ b/patches/wrdu-keyboard@3.0.0.patch @@ -0,0 +1,123 @@ +diff --git a/node_modules/wrdu-keyboard/.DS_Store b/.DS_Store +new file mode 100644 +index 0000000000000000000000000000000000000000..fabbd951c2d14c46fd10fa167b8836d116bc0db6 +Binary files /dev/null and b/.DS_Store differ +diff --git a/dist/runtime/keyboard.d.ts b/dist/runtime/keyboard.d.ts +index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d23c5f1f13 100644 +--- a/dist/runtime/keyboard.d.ts ++++ b/dist/runtime/keyboard.d.ts +@@ -1,15 +1,16 @@ +-import { Key } from './types/keys.js'; +-import { type Plugin } from '#app'; ++import { Key } from "./types/keys.js"; ++import { type Plugin } from "#app"; + type Handler = (event: KeyboardEvent) => void; + type Config = { + once?: boolean; + prevent?: boolean; + }; +-type PublicConfig = Omit; ++type PublicConfig = Omit; + type New = (keys: Key[], handler: Handler, config?: PublicConfig) => void; + export interface Keyboard { + init: () => void; + stop: () => void; ++ unregisterAll: () => void; + down: New; + up: New; + prevent: { +diff --git a/dist/runtime/keyboard.js b/dist/runtime/keyboard.js +index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cdb37820aa 100644 +--- a/dist/runtime/keyboard.js ++++ b/dist/runtime/keyboard.js +@@ -1,13 +1,14 @@ + import { Key } from "./types/keys.js"; + import { defineNuxtPlugin } from "#app"; +-const getKeyString = (keys) => keys[0] == Key.All ? keys.sort().join("+") : "All"; ++const getKeyString = (keys) => keys.includes(Key.All) ? "All" : keys.sort().join("+"); + const handlers = { + down: {}, + up: {} + }; + const pressedKeys = /* @__PURE__ */ new Set(); + const onKeydown = (event) => { +- pressedKeys.add(event.code); ++ const key = event.code; ++ pressedKeys.add(key); + const pressedArray = Array.from(pressedKeys); + const keyString = getKeyString(pressedArray); + if (handlers.down[keyString]) { +@@ -17,13 +18,16 @@ const onKeydown = (event) => { + } + eventHandler.handler(event); + if (eventHandler.once) { +- handlers.down[keyString] = handlers.down[keyString].filter((h) => h !== eventHandler); ++ handlers.down[keyString] = handlers.down[keyString].filter( ++ (h) => h !== eventHandler ++ ); + } + }); + } + }; + const onKeyup = (event) => { +- pressedKeys.delete(event.code); ++ const key = event.code; ++ pressedKeys.delete(key); + const releasedArray = Array.from(pressedKeys); + const keyString = getKeyString(releasedArray); + if (handlers.up[keyString]) { +@@ -33,13 +37,16 @@ const onKeyup = (event) => { + } + eventHandler.handler(event); + if (eventHandler.once) { +- handlers.up[keyString] = handlers.up[keyString].filter((h) => h !== eventHandler); ++ handlers.up[keyString] = handlers.up[keyString].filter( ++ (h) => h !== eventHandler ++ ); + } + }); + } + }; + const init = () => { + stop(); ++ pressedKeys.clear(); + window.addEventListener("keydown", onKeydown); + window.addEventListener("keyup", onKeyup); + }; +@@ -47,6 +54,20 @@ const stop = () => { + window.removeEventListener("keydown", onKeydown); + window.removeEventListener("keyup", onKeyup); + }; ++const unregisterAll = () => { ++ Object.keys(handlers.down).forEach((key) => { ++ handlers.down[key].forEach((handler) => { ++ console.log(`Unregistering ${key} ${handler.handler.toString()}`); ++ }); ++ }); ++ Object.keys(handlers.up).forEach((key) => { ++ handlers.up[key].forEach((handler) => { ++ console.log(`Unregistering ${key} ${handler.handler.toString()}`); ++ }); ++ }); ++ handlers.down = {}; ++ handlers.up = {}; ++}; + const down = (keys, handler, config = {}) => { + if (keys.includes(Key.All)) { + keys = [Key.All]; +@@ -59,6 +80,7 @@ const down = (keys, handler, config = {}) => { + handlers.down[key] = []; + } + const { once = false, prevent = false } = config; ++ console.log(key, handler.toString()); + handlers.down[key].push({ handler, prevent, once }); + }; + const up = (keys, handler, config = {}) => { +@@ -84,6 +106,7 @@ const keyboard = defineNuxtPlugin((nuxtApp) => { + keyboard: { + init, + stop, ++ unregisterAll, + down: (keys, handler, config = {}) => down(keys, handler, config), + up: (keys, handler, config = {}) => up(keys, handler, config), + prevent: { From 6656af8ab1409b91d0f561d100e22dec5b108016 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Thu, 2 Jan 2025 14:54:47 +1000 Subject: [PATCH 109/180] chore: Update wrdu-keyboard to version 3.0.0 --- package.json | 5 ++++- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e605d31..de5e05e 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,12 @@ "sass-embedded": "1.83.0", "uuid": "11.0.3", "vue": "3.5.13", - "wrdu-keyboard": "1.1.1" + "wrdu-keyboard": "3.0.0" }, "overrides": { "chokidar": "^3.6.0" + }, + "patchedDependencies": { + "wrdu-keyboard@3.0.0": "patches/wrdu-keyboard@3.0.0.patch" } } diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 31fba10..a5d7869 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4054,7 +4054,7 @@ dependencies = [ [[package]] name = "qopy" -version = "0.3.3" +version = "0.3.4" dependencies = [ "active-win-pos-rs", "applications", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 08142a1..45e9dd7 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "qopy" -version = "0.3.3" +version = "0.3.4" description = "Qopy" authors = ["pandadev"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 2cfde48..10ae2a2 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,6 +1,6 @@ { "productName": "Qopy", - "version": "0.3.3", + "version": "0.3.4", "identifier": "net.pandadev.qopy", "build": { "frontendDist": "../dist", From 0c28a5b0dbc9c7e1668a515e4109eb21c691d386 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:05:02 +1000 Subject: [PATCH 110/180] refactor: improve keybind saving logic and error handling --- GET_STARTED.md | 4 +- pages/settings.vue | 71 ++++------ patches/wrdu-keyboard@3.0.0.patch | 98 +++++++------- src-tauri/src/api/hotkeys.rs | 114 ++++++++-------- src-tauri/src/db/settings.rs | 9 +- src-tauri/src/utils/keys.rs | 118 ++++++++++++++++ src-tauri/src/utils/mod.rs | 1 + types/keys.ts | 217 ++++++++++++++++++++++++++++++ 8 files changed, 478 insertions(+), 154 deletions(-) create mode 100644 src-tauri/src/utils/keys.rs create mode 100644 types/keys.ts diff --git a/GET_STARTED.md b/GET_STARTED.md index 548a5e9..a793041 100644 --- a/GET_STARTED.md +++ b/GET_STARTED.md @@ -1,6 +1,6 @@ # Get Started -The default hotkey for Qopy is Windows+V which is also the hotkey for the default clipboard manager to turn that off follow [this guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md#disable-windowsv-for-default-clipboard-manager). +The default hotkey for Qopy is Windows+V which is also the hotkey for the default clipboard manager to turn that off follow [this guide](https://github.com/0PandaDEV/Qopy/blob/main/GET_STARTED.md#disable-windowsv-for-default-clipboard-manager). All the data of Qopy is stored inside of a SQLite database. @@ -12,7 +12,7 @@ All the data of Qopy is stored inside of a SQLite database. ## Disable Windows+V for default clipboard manager -https://github.com/user-attachments/assets/723f9e07-3190-46ec-9bb7-15dfc112f620 + To disable the default clipboard manager popup from windows open Command prompt and run this command diff --git a/pages/settings.vue b/pages/settings.vue index cf4771e..7a20eb1 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -33,7 +33,6 @@
@@ -44,7 +43,7 @@ class="key" :class="{ modifier: isModifier(key) }" v-for="(key, index) in keybind"> - {{ keyToDisplay(key) }} + {{ keyToLabel(key) }}
@@ -58,10 +57,11 @@ import { onMounted, onUnmounted, reactive, ref } from "vue"; import { platform } from "@tauri-apps/plugin-os"; import { useRouter } from "vue-router"; import { Key } from "wrdu-keyboard/key"; +import { KeyValues, KeyLabels } from "../types/keys"; -const activeModifiers = reactive>(new Set()); +const activeModifiers = reactive>(new Set()); const isKeybindInputFocused = ref(false); -const keybind = ref([]); +const keybind = ref([]); const keybindInput = ref(null); const lastBlurTime = ref(0); const os = ref(""); @@ -69,52 +69,27 @@ const router = useRouter(); const keyboard = useKeyboard(); const showEmptyKeybindError = ref(false); -const keyToDisplayMap: Record = { - " ": "Space", - Alt: "Alt", - AltLeft: "Alt L", - AltRight: "Alt R", - ArrowDown: "↓", - ArrowLeft: "←", - ArrowRight: "→", - ArrowUp: "↑", - Control: "Ctrl", - ControlLeft: "Ctrl L", - ControlRight: "Ctrl R", - Enter: "↵", - Meta: "Meta", - MetaLeft: "Meta L", - MetaRight: "Meta R", - Shift: "⇧", - ShiftLeft: "⇧ L", - ShiftRight: "⇧ R", -}; - const modifierKeySet = new Set([ - "Alt", - "AltLeft", - "AltRight", - "Control", - "ControlLeft", - "ControlRight", - "Meta", - "MetaLeft", - "MetaRight", - "Shift", - "ShiftLeft", - "ShiftRight", + KeyValues.AltLeft, + KeyValues.AltRight, + KeyValues.ControlLeft, + KeyValues.ControlRight, + KeyValues.MetaLeft, + KeyValues.MetaRight, + KeyValues.ShiftLeft, + KeyValues.ShiftRight, ]); -const isModifier = (key: string): boolean => { +const isModifier = (key: KeyValues): boolean => { return modifierKeySet.has(key); }; -const keyToDisplay = (key: string): string => { - return keyToDisplayMap[key] || key; +const keyToLabel = (key: KeyValues): string => { + return KeyLabels[key] || key; }; const updateKeybind = () => { - const modifiers = Array.from(activeModifiers).sort(); + const modifiers = Array.from(activeModifiers); const nonModifiers = keybind.value.filter((key) => !isModifier(key)); keybind.value = [...modifiers, ...nonModifiers]; }; @@ -133,9 +108,9 @@ const onFocus = () => { }; const onKeyDown = (event: KeyboardEvent) => { - const key = event.code; + const key = event.code as KeyValues; - if (key === "Escape") { + if (key === KeyValues.Escape) { if (keybindInput.value) { keybindInput.value.blur(); } @@ -155,8 +130,7 @@ const onKeyDown = (event: KeyboardEvent) => { const saveKeybind = async () => { if (keybind.value.length > 0) { - console.log("Saving keybind", keybind.value); - await invoke("save_keybind", { keybind: keybind }); + await invoke("save_keybind", { keybind: keybind.value }); } else { showEmptyKeybindError.value = true; } @@ -165,8 +139,13 @@ const saveKeybind = async () => { os.value = platform(); onMounted(() => { + keyboard.down([Key.All], (event) => { + if (isKeybindInputFocused.value) { + onKeyDown(event); + } + }); + keyboard.down([Key.Escape], (event) => { - console.log("Escape key pressed"); if (isKeybindInputFocused.value) { keybindInput.value?.blur(); } else { diff --git a/patches/wrdu-keyboard@3.0.0.patch b/patches/wrdu-keyboard@3.0.0.patch index e973647..bc77583 100644 --- a/patches/wrdu-keyboard@3.0.0.patch +++ b/patches/wrdu-keyboard@3.0.0.patch @@ -1,6 +1,6 @@ diff --git a/node_modules/wrdu-keyboard/.DS_Store b/.DS_Store new file mode 100644 -index 0000000000000000000000000000000000000000..fabbd951c2d14c46fd10fa167b8836d116bc0db6 +index 0000000000000000000000000000000000000000..4b7e9446f3580fab3e4feaba097bcdaf98c5833c Binary files /dev/null and b/.DS_Store differ diff --git a/dist/runtime/keyboard.d.ts b/dist/runtime/keyboard.d.ts index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d23c5f1f13 100644 @@ -27,10 +27,10 @@ index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d2 up: New; prevent: { diff --git a/dist/runtime/keyboard.js b/dist/runtime/keyboard.js -index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cdb37820aa 100644 +index e16f600258cee90d185ffc52777bed95c14bd93e..5ddec447a5dc66ffe063eb9f9dd765c9045bdaf7 100644 --- a/dist/runtime/keyboard.js +++ b/dist/runtime/keyboard.js -@@ -1,13 +1,14 @@ +@@ -1,45 +1,54 @@ import { Key } from "./types/keys.js"; import { defineNuxtPlugin } from "#app"; -const getKeyString = (keys) => keys[0] == Key.All ? keys.sort().join("+") : "All"; @@ -45,18 +45,31 @@ index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cd + const key = event.code; + pressedKeys.add(key); const pressedArray = Array.from(pressedKeys); - const keyString = getKeyString(pressedArray); - if (handlers.down[keyString]) { -@@ -17,13 +18,16 @@ const onKeydown = (event) => { - } - eventHandler.handler(event); - if (eventHandler.once) { +- const keyString = getKeyString(pressedArray); +- if (handlers.down[keyString]) { +- handlers.down[keyString].forEach((eventHandler) => { +- if (eventHandler.prevent) { +- event.preventDefault(); +- } +- eventHandler.handler(event); +- if (eventHandler.once) { - handlers.down[keyString] = handlers.down[keyString].filter((h) => h !== eventHandler); -+ handlers.down[keyString] = handlers.down[keyString].filter( -+ (h) => h !== eventHandler -+ ); - } - }); +- } +- }); ++ for (const keyString of [getKeyString(pressedArray), "All"]) { ++ if (handlers.down[keyString]) { ++ handlers.down[keyString].forEach((eventHandler) => { ++ if (eventHandler.prevent) { ++ event.preventDefault(); ++ } ++ eventHandler.handler(event); ++ if (eventHandler.once) { ++ handlers.down[keyString] = handlers.down[keyString].filter( ++ (h) => h !== eventHandler ++ ); ++ } ++ }); ++ } } }; const onKeyup = (event) => { @@ -64,18 +77,31 @@ index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cd + const key = event.code; + pressedKeys.delete(key); const releasedArray = Array.from(pressedKeys); - const keyString = getKeyString(releasedArray); - if (handlers.up[keyString]) { -@@ -33,13 +37,16 @@ const onKeyup = (event) => { - } - eventHandler.handler(event); - if (eventHandler.once) { +- const keyString = getKeyString(releasedArray); +- if (handlers.up[keyString]) { +- handlers.up[keyString].forEach((eventHandler) => { +- if (eventHandler.prevent) { +- event.preventDefault(); +- } +- eventHandler.handler(event); +- if (eventHandler.once) { - handlers.up[keyString] = handlers.up[keyString].filter((h) => h !== eventHandler); -+ handlers.up[keyString] = handlers.up[keyString].filter( -+ (h) => h !== eventHandler -+ ); - } - }); +- } +- }); ++ for (const keyString of [getKeyString(releasedArray), "All"]) { ++ if (handlers.up[keyString]) { ++ handlers.up[keyString].forEach((eventHandler) => { ++ if (eventHandler.prevent) { ++ event.preventDefault(); ++ } ++ eventHandler.handler(event); ++ if (eventHandler.once) { ++ handlers.up[keyString] = handlers.up[keyString].filter( ++ (h) => h !== eventHandler ++ ); ++ } ++ }); ++ } } }; const init = () => { @@ -84,36 +110,18 @@ index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cd window.addEventListener("keydown", onKeydown); window.addEventListener("keyup", onKeyup); }; -@@ -47,6 +54,20 @@ const stop = () => { +@@ -47,6 +56,10 @@ const stop = () => { window.removeEventListener("keydown", onKeydown); window.removeEventListener("keyup", onKeyup); }; +const unregisterAll = () => { -+ Object.keys(handlers.down).forEach((key) => { -+ handlers.down[key].forEach((handler) => { -+ console.log(`Unregistering ${key} ${handler.handler.toString()}`); -+ }); -+ }); -+ Object.keys(handlers.up).forEach((key) => { -+ handlers.up[key].forEach((handler) => { -+ console.log(`Unregistering ${key} ${handler.handler.toString()}`); -+ }); -+ }); + handlers.down = {}; + handlers.up = {}; +}; const down = (keys, handler, config = {}) => { if (keys.includes(Key.All)) { keys = [Key.All]; -@@ -59,6 +80,7 @@ const down = (keys, handler, config = {}) => { - handlers.down[key] = []; - } - const { once = false, prevent = false } = config; -+ console.log(key, handler.toString()); - handlers.down[key].push({ handler, prevent, once }); - }; - const up = (keys, handler, config = {}) => { -@@ -84,6 +106,7 @@ const keyboard = defineNuxtPlugin((nuxtApp) => { +@@ -84,6 +97,7 @@ const keyboard = defineNuxtPlugin((nuxtApp) => { keyboard: { init, stop, diff --git a/src-tauri/src/api/hotkeys.rs b/src-tauri/src/api/hotkeys.rs index 0470e24..52a276b 100644 --- a/src-tauri/src/api/hotkeys.rs +++ b/src-tauri/src/api/hotkeys.rs @@ -1,48 +1,61 @@ -use tauri_plugin_aptabase::EventTracker; use crate::utils::commands::center_window_on_current_monitor; +use crate::utils::keys::KeyCode; use global_hotkey::{ hotkey::{Code, HotKey, Modifiers}, GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState, }; -use std::cell::RefCell; +use lazy_static::lazy_static; use std::str::FromStr; +use std::sync::Mutex; use tauri::{AppHandle, Listener, Manager}; +use tauri_plugin_aptabase::EventTracker; -thread_local! { - static HOTKEY_MANAGER: RefCell> = RefCell::new(None); +lazy_static! { + static ref HOTKEY_MANAGER: Mutex> = Mutex::new(None); + static ref REGISTERED_HOTKEYS: Mutex> = Mutex::new(Vec::new()); } pub fn setup(app_handle: tauri::AppHandle) { let app_handle_clone = app_handle.clone(); - let manager = GlobalHotKeyManager::new().expect("Failed to initialize hotkey manager"); - HOTKEY_MANAGER.with(|m| *m.borrow_mut() = Some(manager)); + let manager = match GlobalHotKeyManager::new() { + Ok(manager) => manager, + Err(err) => { + eprintln!("Failed to initialize hotkey manager: {:?}", err); + return; + } + }; + + { + let mut manager_guard = HOTKEY_MANAGER.lock().unwrap(); + *manager_guard = Some(manager); + } let rt = app_handle.state::(); let initial_keybind = rt .block_on(crate::db::settings::get_keybind(app_handle_clone.clone())) .expect("Failed to get initial keybind"); - let initial_shortcut = initial_keybind.join("+"); - let initial_shortcut_for_update = initial_shortcut.clone(); - let initial_shortcut_for_save = initial_shortcut.clone(); + let initial_shortcut_for_update = initial_keybind.clone(); + let initial_shortcut_for_save = initial_keybind.clone(); - if let Err(e) = register_shortcut(&initial_shortcut) { + if let Err(e) = register_shortcut(&initial_keybind) { eprintln!("Error registering initial shortcut: {:?}", e); } app_handle.listen("update-shortcut", move |event| { - let payload_str = event.payload().to_string(); + let payload_str = event.payload(); if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_update) { - HOTKEY_MANAGER.with(|manager| { - if let Some(manager) = manager.borrow().as_ref() { - let _ = manager.unregister(old_hotkey); - } - }); + let manager_guard = HOTKEY_MANAGER.lock().unwrap(); + if let Some(manager) = manager_guard.as_ref() { + let _ = manager.unregister(old_hotkey); + } } - if let Err(e) = register_shortcut(&payload_str) { + let payload: Vec = serde_json::from_str(payload_str).unwrap_or_default(); + + if let Err(e) = register_shortcut(&payload) { eprintln!("Error re-registering shortcut: {:?}", e); } }); @@ -51,14 +64,14 @@ pub fn setup(app_handle: tauri::AppHandle) { let payload_str = event.payload().to_string(); if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_save) { - HOTKEY_MANAGER.with(|manager| { - if let Some(manager) = manager.borrow().as_ref() { - let _ = manager.unregister(old_hotkey); - } - }); + let manager_guard = HOTKEY_MANAGER.lock().unwrap(); + if let Some(manager) = manager_guard.as_ref() { + let _ = manager.unregister(old_hotkey); + } } - if let Err(e) = register_shortcut(&payload_str) { + let payload: Vec = serde_json::from_str(&payload_str).unwrap_or_default(); + if let Err(e) = register_shortcut(&payload) { eprintln!("Error registering saved shortcut: {:?}", e); } }); @@ -81,48 +94,36 @@ pub fn setup(app_handle: tauri::AppHandle) { }); } -fn register_shortcut(shortcut: &str) -> Result<(), Box> { +fn register_shortcut(shortcut: &[String]) -> Result<(), Box> { let hotkey = parse_hotkey(shortcut)?; - HOTKEY_MANAGER.with(|manager| { - if let Some(manager) = manager.borrow().as_ref() { - manager.register(hotkey)?; - } + + let manager_guard = HOTKEY_MANAGER.lock().unwrap(); + if let Some(manager) = manager_guard.as_ref() { + manager.register(hotkey.clone())?; + REGISTERED_HOTKEYS.lock().unwrap().push(hotkey); Ok(()) - }) + } else { + Err("Hotkey manager not initialized".into()) + } } -fn parse_hotkey(shortcut: &str) -> Result> { +fn parse_hotkey(shortcut: &[String]) -> Result> { let mut modifiers = Modifiers::empty(); let mut code = None; - let shortcut = shortcut.replace("\"", ""); - - for part in shortcut.split('+') { - let part = part.trim().to_lowercase(); + for part in shortcut { match part.as_str() { - "ctrl" | "control" | "controlleft" => modifiers |= Modifiers::CONTROL, - "alt" | "altleft" | "optionleft" => modifiers |= Modifiers::ALT, - "shift" | "shiftleft" => modifiers |= Modifiers::SHIFT, - "super" | "meta" | "cmd" | "metaleft" => modifiers |= Modifiers::META, + "ControlLeft" => modifiers |= Modifiers::CONTROL, + "AltLeft" => modifiers |= Modifiers::ALT, + "ShiftLeft" => modifiers |= Modifiers::SHIFT, + "MetaLeft" => modifiers |= Modifiers::META, key => { - let key_code = if key.starts_with("key") { - "Key".to_string() + &key[3..].to_uppercase() - } else if key.len() == 1 && key.chars().next().unwrap().is_alphabetic() { - "Key".to_string() + &key.to_uppercase() - } else { - key.to_string() - }; - - code = Some( - Code::from_str(&key_code) - .map_err(|_| format!("Invalid key code: {}", key_code))?, - ); + code = Some(Code::from(KeyCode::from_str(key)?)); } } } - let key_code = - code.ok_or_else(|| format!("No valid key code found in shortcut: {}", shortcut))?; + let key_code = code.ok_or_else(|| "No valid key code found".to_string())?; Ok(HotKey::new(Some(modifiers), key_code)) } @@ -144,7 +145,10 @@ fn handle_hotkey_event(app_handle: &AppHandle) { center_window_on_current_monitor(&window); } - let _ = app_handle.track_event("hotkey_triggered", Some(serde_json::json!({ - "action": if window.is_visible().unwrap() { "hide" } else { "show" } - }))); + let _ = app_handle.track_event( + "hotkey_triggered", + Some(serde_json::json!({ + "action": if window.is_visible().unwrap() { "hide" } else { "show" } + })), + ); } diff --git a/src-tauri/src/db/settings.rs b/src-tauri/src/db/settings.rs index bdd6f58..7fedf8c 100644 --- a/src-tauri/src/db/settings.rs +++ b/src-tauri/src/db/settings.rs @@ -30,11 +30,8 @@ pub async fn save_keybind( pool: tauri::State<'_, SqlitePool>, keybind: Vec, ) -> Result<(), String> { - let keybind_str = keybind.join("+"); - let keybind_clone = keybind_str.clone(); - app_handle - .emit("update-shortcut", &keybind_str) + .emit("update-shortcut", &keybind) .map_err(|e| e.to_string())?; let json = serde_json::to_string(&keybind).map_err(|e| e.to_string())?; @@ -46,7 +43,7 @@ pub async fn save_keybind( .map_err(|e| e.to_string())?; let _ = app_handle.track_event("keybind_saved", Some(serde_json::json!({ - "keybind": keybind_clone + "keybind": keybind }))); Ok(()) @@ -97,7 +94,7 @@ pub async fn get_keybind(app_handle: tauri::AppHandle) -> Result, St .map_err(|e| e.to_string())?; let json = row.map(|r| r.get::("value")).unwrap_or_else(|| { - serde_json::to_string(&vec!["Meta".to_string(), "V".to_string()]) + serde_json::to_string(&vec!["MetaLeft".to_string(), "KeyV".to_string()]) .expect("Failed to serialize default keybind") }); diff --git a/src-tauri/src/utils/keys.rs b/src-tauri/src/utils/keys.rs new file mode 100644 index 0000000..fffacdd --- /dev/null +++ b/src-tauri/src/utils/keys.rs @@ -0,0 +1,118 @@ +use global_hotkey::hotkey::Code; +use std::str::FromStr; + +pub struct KeyCode(Code); + +impl FromStr for KeyCode { + type Err = String; + + fn from_str(s: &str) -> Result { + let code = match s { + "Backquote" => Code::Backquote, + "Backslash" => Code::Backslash, + "BracketLeft" => Code::BracketLeft, + "BracketRight" => Code::BracketRight, + "Comma" => Code::Comma, + "Digit0" => Code::Digit0, + "Digit1" => Code::Digit1, + "Digit2" => Code::Digit2, + "Digit3" => Code::Digit3, + "Digit4" => Code::Digit4, + "Digit5" => Code::Digit5, + "Digit6" => Code::Digit6, + "Digit7" => Code::Digit7, + "Digit8" => Code::Digit8, + "Digit9" => Code::Digit9, + "Equal" => Code::Equal, + "KeyA" => Code::KeyA, + "KeyB" => Code::KeyB, + "KeyC" => Code::KeyC, + "KeyD" => Code::KeyD, + "KeyE" => Code::KeyE, + "KeyF" => Code::KeyF, + "KeyG" => Code::KeyG, + "KeyH" => Code::KeyH, + "KeyI" => Code::KeyI, + "KeyJ" => Code::KeyJ, + "KeyK" => Code::KeyK, + "KeyL" => Code::KeyL, + "KeyM" => Code::KeyM, + "KeyN" => Code::KeyN, + "KeyO" => Code::KeyO, + "KeyP" => Code::KeyP, + "KeyQ" => Code::KeyQ, + "KeyR" => Code::KeyR, + "KeyS" => Code::KeyS, + "KeyT" => Code::KeyT, + "KeyU" => Code::KeyU, + "KeyV" => Code::KeyV, + "KeyW" => Code::KeyW, + "KeyX" => Code::KeyX, + "KeyY" => Code::KeyY, + "KeyZ" => Code::KeyZ, + "Minus" => Code::Minus, + "Period" => Code::Period, + "Quote" => Code::Quote, + "Semicolon" => Code::Semicolon, + "Slash" => Code::Slash, + "Backspace" => Code::Backspace, + "CapsLock" => Code::CapsLock, + "Delete" => Code::Delete, + "Enter" => Code::Enter, + "Space" => Code::Space, + "Tab" => Code::Tab, + "End" => Code::End, + "Home" => Code::Home, + "Insert" => Code::Insert, + "PageDown" => Code::PageDown, + "PageUp" => Code::PageUp, + "ArrowDown" => Code::ArrowDown, + "ArrowLeft" => Code::ArrowLeft, + "ArrowRight" => Code::ArrowRight, + "ArrowUp" => Code::ArrowUp, + "NumLock" => Code::NumLock, + "Numpad0" => Code::Numpad0, + "Numpad1" => Code::Numpad1, + "Numpad2" => Code::Numpad2, + "Numpad3" => Code::Numpad3, + "Numpad4" => Code::Numpad4, + "Numpad5" => Code::Numpad5, + "Numpad6" => Code::Numpad6, + "Numpad7" => Code::Numpad7, + "Numpad8" => Code::Numpad8, + "Numpad9" => Code::Numpad9, + "NumpadAdd" => Code::NumpadAdd, + "NumpadDecimal" => Code::NumpadDecimal, + "NumpadDivide" => Code::NumpadDivide, + "NumpadMultiply" => Code::NumpadMultiply, + "NumpadSubtract" => Code::NumpadSubtract, + "Escape" => Code::Escape, + "PrintScreen" => Code::PrintScreen, + "ScrollLock" => Code::ScrollLock, + "Pause" => Code::Pause, + "AudioVolumeDown" => Code::AudioVolumeDown, + "AudioVolumeMute" => Code::AudioVolumeMute, + "AudioVolumeUp" => Code::AudioVolumeUp, + "F1" => Code::F1, + "F2" => Code::F2, + "F3" => Code::F3, + "F4" => Code::F4, + "F5" => Code::F5, + "F6" => Code::F6, + "F7" => Code::F7, + "F8" => Code::F8, + "F9" => Code::F9, + "F10" => Code::F10, + "F11" => Code::F11, + "F12" => Code::F12, + _ => return Err(format!("Unknown key code: {}", s)), + }; + Ok(KeyCode(code)) + } +} + +impl From for Code { + fn from(key_code: KeyCode) -> Self { + key_code.0 + } +} diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index b888b1f..9554229 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -2,3 +2,4 @@ pub mod commands; pub mod favicon; pub mod types; pub mod logger; +pub mod keys; \ No newline at end of file diff --git a/types/keys.ts b/types/keys.ts new file mode 100644 index 0000000..d81454f --- /dev/null +++ b/types/keys.ts @@ -0,0 +1,217 @@ +export enum KeyValues { + Backquote = 'Backquote', + Backslash = 'Backslash', + BracketLeft = 'BracketLeft', + BracketRight = 'BracketRight', + Comma = 'Comma', + Digit0 = 'Digit0', + Digit1 = 'Digit1', + Digit2 = 'Digit2', + Digit3 = 'Digit3', + Digit4 = 'Digit4', + Digit5 = 'Digit5', + Digit6 = 'Digit6', + Digit7 = 'Digit7', + Digit8 = 'Digit8', + Digit9 = 'Digit9', + Equal = 'Equal', + KeyA = 'KeyA', + KeyB = 'KeyB', + KeyC = 'KeyC', + KeyD = 'KeyD', + KeyE = 'KeyE', + KeyF = 'KeyF', + KeyG = 'KeyG', + KeyH = 'KeyH', + KeyI = 'KeyI', + KeyJ = 'KeyJ', + KeyK = 'KeyK', + KeyL = 'KeyL', + KeyM = 'KeyM', + KeyN = 'KeyN', + KeyO = 'KeyO', + KeyP = 'KeyP', + KeyQ = 'KeyQ', + KeyR = 'KeyR', + KeyS = 'KeyS', + KeyT = 'KeyT', + KeyU = 'KeyU', + KeyV = 'KeyV', + KeyW = 'KeyW', + KeyX = 'KeyX', + KeyY = 'KeyY', + KeyZ = 'KeyZ', + Minus = 'Minus', + Period = 'Period', + Quote = 'Quote', + Semicolon = 'Semicolon', + Slash = 'Slash', + AltLeft = 'AltLeft', + AltRight = 'AltRight', + Backspace = 'Backspace', + CapsLock = 'CapsLock', + ContextMenu = 'ContextMenu', + ControlLeft = 'ControlLeft', + ControlRight = 'ControlRight', + Enter = 'Enter', + MetaLeft = 'MetaLeft', + MetaRight = 'MetaRight', + ShiftLeft = 'ShiftLeft', + ShiftRight = 'ShiftRight', + Space = 'Space', + Tab = 'Tab', + Delete = 'Delete', + End = 'End', + Home = 'Home', + Insert = 'Insert', + PageDown = 'PageDown', + PageUp = 'PageUp', + ArrowDown = 'ArrowDown', + ArrowLeft = 'ArrowLeft', + ArrowRight = 'ArrowRight', + ArrowUp = 'ArrowUp', + NumLock = 'NumLock', + Numpad0 = 'Numpad0', + Numpad1 = 'Numpad1', + Numpad2 = 'Numpad2', + Numpad3 = 'Numpad3', + Numpad4 = 'Numpad4', + Numpad5 = 'Numpad5', + Numpad6 = 'Numpad6', + Numpad7 = 'Numpad7', + Numpad8 = 'Numpad8', + Numpad9 = 'Numpad9', + NumpadAdd = 'NumpadAdd', + NumpadDecimal = 'NumpadDecimal', + NumpadDivide = 'NumpadDivide', + NumpadMultiply = 'NumpadMultiply', + NumpadSubtract = 'NumpadSubtract', + Escape = 'Escape', + PrintScreen = 'PrintScreen', + ScrollLock = 'ScrollLock', + Pause = 'Pause', + AudioVolumeDown = 'AudioVolumeDown', + AudioVolumeMute = 'AudioVolumeMute', + AudioVolumeUp = 'AudioVolumeUp', + F1 = 'F1', + F2 = 'F2', + F3 = 'F3', + F4 = 'F4', + F5 = 'F5', + F6 = 'F6', + F7 = 'F7', + F8 = 'F8', + F9 = 'F9', + F10 = 'F10', + F11 = 'F11', + F12 = 'F12', +} + +export enum KeyLabels { + Backquote = '`', + Backslash = '\\', + BracketLeft = '[', + BracketRight = ']', + Comma = ',', + Digit0 = '0', + Digit1 = '1', + Digit2 = '2', + Digit3 = '3', + Digit4 = '4', + Digit5 = '5', + Digit6 = '6', + Digit7 = '7', + Digit8 = '8', + Digit9 = '9', + Equal = '=', + KeyA = 'A', + KeyB = 'B', + KeyC = 'C', + KeyD = 'D', + KeyE = 'E', + KeyF = 'F', + KeyG = 'G', + KeyH = 'H', + KeyI = 'I', + KeyJ = 'J', + KeyK = 'K', + KeyL = 'L', + KeyM = 'M', + KeyN = 'N', + KeyO = 'O', + KeyP = 'P', + KeyQ = 'Q', + KeyR = 'R', + KeyS = 'S', + KeyT = 'T', + KeyU = 'U', + KeyV = 'V', + KeyW = 'W', + KeyX = 'X', + KeyY = 'Y', + KeyZ = 'Z', + Minus = '-', + Period = '.', + Quote = "'", + Semicolon = ';', + Slash = '/', + AltLeft = 'Alt', + AltRight = 'Alt (Right)', + Backspace = 'Backspace', + CapsLock = 'Caps Lock', + ContextMenu = 'Context Menu', + ControlLeft = 'Ctrl', + ControlRight = 'Ctrl (Right)', + Enter = 'Enter', + MetaLeft = 'Meta', + MetaRight = 'Meta (Right)', + ShiftLeft = 'Shift', + ShiftRight = 'Shift (Right)', + Space = 'Space', + Tab = 'Tab', + Delete = 'Delete', + End = 'End', + Home = 'Home', + Insert = 'Insert', + PageDown = 'Page Down', + PageUp = 'Page Up', + ArrowDown = '↓', + ArrowLeft = '←', + ArrowRight = '→', + ArrowUp = '↑', + NumLock = 'Num Lock', + Numpad0 = 'Numpad 0', + Numpad1 = 'Numpad 1', + Numpad2 = 'Numpad 2', + Numpad3 = 'Numpad 3', + Numpad4 = 'Numpad 4', + Numpad5 = 'Numpad 5', + Numpad6 = 'Numpad 6', + Numpad7 = 'Numpad 7', + Numpad8 = 'Numpad 8', + Numpad9 = 'Numpad 9', + NumpadAdd = 'Numpad +', + NumpadDecimal = 'Numpad .', + NumpadDivide = 'Numpad /', + NumpadMultiply = 'Numpad *', + NumpadSubtract = 'Numpad -', + Escape = 'Esc', + PrintScreen = 'Print Screen', + ScrollLock = 'Scroll Lock', + Pause = 'Pause', + AudioVolumeDown = 'Volume Down', + AudioVolumeMute = 'Volume Mute', + AudioVolumeUp = 'Volume Up', + F1 = 'F1', + F2 = 'F2', + F3 = 'F3', + F4 = 'F4', + F5 = 'F5', + F6 = 'F6', + F7 = 'F7', + F8 = 'F8', + F9 = 'F9', + F10 = 'F10', + F11 = 'F11', + F12 = 'F12', +} \ No newline at end of file From c872490a9576e5a79d015bc2891634f9bfa68f3f Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:10:09 +1000 Subject: [PATCH 111/180] feat: add redirect after saving keybind in settings.vue --- pages/settings.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/settings.vue b/pages/settings.vue index 7a20eb1..52f84d3 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -131,6 +131,7 @@ const onKeyDown = (event: KeyboardEvent) => { const saveKeybind = async () => { if (keybind.value.length > 0) { await invoke("save_keybind", { keybind: keybind.value }); + router.push("/"); } else { showEmptyKeybindError.value = true; } From 80545504435ef5b1c55f32df6bff6318bccf3f97 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:10:46 +1000 Subject: [PATCH 112/180] fix: old hotkey not getting unregistered correctly --- src-tauri/src/api/hotkeys.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src-tauri/src/api/hotkeys.rs b/src-tauri/src/api/hotkeys.rs index 52a276b..69ee336 100644 --- a/src-tauri/src/api/hotkeys.rs +++ b/src-tauri/src/api/hotkeys.rs @@ -12,7 +12,7 @@ use tauri_plugin_aptabase::EventTracker; lazy_static! { static ref HOTKEY_MANAGER: Mutex> = Mutex::new(None); - static ref REGISTERED_HOTKEYS: Mutex> = Mutex::new(Vec::new()); + static ref REGISTERED_HOTKEY: Mutex> = Mutex::new(None); } pub fn setup(app_handle: tauri::AppHandle) { @@ -36,9 +36,6 @@ pub fn setup(app_handle: tauri::AppHandle) { .block_on(crate::db::settings::get_keybind(app_handle_clone.clone())) .expect("Failed to get initial keybind"); - let initial_shortcut_for_update = initial_keybind.clone(); - let initial_shortcut_for_save = initial_keybind.clone(); - if let Err(e) = register_shortcut(&initial_keybind) { eprintln!("Error registering initial shortcut: {:?}", e); } @@ -46,7 +43,7 @@ pub fn setup(app_handle: tauri::AppHandle) { app_handle.listen("update-shortcut", move |event| { let payload_str = event.payload(); - if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_update) { + if let Some(old_hotkey) = REGISTERED_HOTKEY.lock().unwrap().take() { let manager_guard = HOTKEY_MANAGER.lock().unwrap(); if let Some(manager) = manager_guard.as_ref() { let _ = manager.unregister(old_hotkey); @@ -63,7 +60,7 @@ pub fn setup(app_handle: tauri::AppHandle) { app_handle.listen("save_keybind", move |event| { let payload_str = event.payload().to_string(); - if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_for_save) { + if let Some(old_hotkey) = REGISTERED_HOTKEY.lock().unwrap().take() { let manager_guard = HOTKEY_MANAGER.lock().unwrap(); if let Some(manager) = manager_guard.as_ref() { let _ = manager.unregister(old_hotkey); @@ -100,7 +97,7 @@ fn register_shortcut(shortcut: &[String]) -> Result<(), Box Date: Thu, 2 Jan 2025 18:40:55 +1000 Subject: [PATCH 113/180] fix: spacing of main ui --- assets/css/index.scss | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/assets/css/index.scss b/assets/css/index.scss index 2fb355a..5feb44b 100644 --- a/assets/css/index.scss +++ b/assets/css/index.scss @@ -22,7 +22,7 @@ $mutedtext: #78756f; position: fixed; top: 0; left: 0; - height: 54px; + height: 56px; background-color: transparent; outline: none; border: none; @@ -35,10 +35,10 @@ $mutedtext: #78756f; .results { position: absolute; - width: 284px; - top: 53px; + width: 286px; + top: 55px; left: 0; - height: calc(100vh - 95px); + height: 417px; border-right: 1px solid $divider; display: flex; flex-direction: column; @@ -46,6 +46,7 @@ $mutedtext: #78756f; padding-bottom: 8px; overflow-y: auto; overflow-x: hidden; + z-index: 3; .result { height: 40px; @@ -59,6 +60,7 @@ $mutedtext: #78756f; overflow: hidden; text-overflow: clip; white-space: nowrap; + color: $text; } .result { @@ -96,20 +98,22 @@ $mutedtext: #78756f; .content { position: absolute; - top: 53px; - left: 284px; - height: calc(100vh - 254px); + top: 55px; + left: 285px; + height: 220px; font-family: CommitMono !important; font-size: 12px; letter-spacing: 1; border-radius: 10px; - width: calc(100vw - 286px); + width: 465px; white-space: pre-wrap; word-wrap: break-word; display: flex; flex-direction: column; align-items: center; overflow: hidden; + z-index: 2; + color: $text; &:not(:has(.image)) { padding: 8px; @@ -128,7 +132,7 @@ $mutedtext: #78756f; } .bottom-bar { - height: 40px; + height: 39px; width: calc(100vw - 2px); backdrop-filter: blur(18px); background-color: hsla(40, 3%, 16%, 0.8); @@ -215,18 +219,20 @@ $mutedtext: #78756f; display: flex; flex-direction: column; gap: 14px; - bottom: 40px; - left: 284px; + bottom: 39px; + left: 285px; height: 160px; - width: calc(100vw - 286px); + width: 465px; border-top: 1px solid $divider; background-color: $primary; padding: 14px; + z-index: 1; .title { font-family: SFRoundedSemiBold; font-size: 12px; letter-spacing: 0.6px; + color: $text; } .info-content { From 6d7874c1aef9605f189377d6959fb52ea405accb Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:41:10 +1000 Subject: [PATCH 114/180] feat: new settings ui --- assets/css/settings.scss | 133 ++++++++++++++++++++++++++++++--------- pages/settings.vue | 103 ++++++++++++++++++++++-------- 2 files changed, 179 insertions(+), 57 deletions(-) diff --git a/assets/css/settings.scss b/assets/css/settings.scss index 39bae81..70b1c53 100644 --- a/assets/css/settings.scss +++ b/assets/css/settings.scss @@ -36,49 +36,116 @@ $mutedtext: #78756f; } } -.keybind-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; - gap: 6px; - z-index: -1; +p { + font-family: SFRoundedMedium; +} - .title { - font-size: 20px; - font-weight: 800; - } +.settings-container { + width: 100%; + margin-top: 26px; + position: relative; + font-size: 12px; + font-family: SFRoundedMedium; - .keybind-input { - padding: 6px; - border: 1px solid $divider; - color: $text2; + .settings { + position: absolute; + left: 50%; + transform: translateX(-50%); + margin-left: -26px; display: flex; - border-radius: 13px; - outline: none; - gap: 6px; + gap: 24px; - .key { - color: $text2; - font-family: SFRoundedMedium; - background-color: $divider; - padding: 6px 8px; - border-radius: 8px; + .names { + display: flex; + flex-direction: column; + gap: 16px; + + p { + font-family: SFRoundedSemiBold; + color: $text2; + } + } + + .actions { + display: flex; + flex-direction: column; + gap: 16px; + color: $mutedtext; + } + } +} + +.launch { + display: flex; + align-items: center; + gap: 6px; + + input[type="checkbox"] { + appearance: none; + width: 14px; + height: 14px; + background-color: transparent; + border-radius: 5px; + border: 1px solid $mutedtext; + position: relative; + cursor: pointer; + transition: background-color 0.2s; + + &:checked { + ~ .checkmark { + opacity: 1; + } } } - .keybind-input:focus { - border: 1px solid rgba(255, 255, 255, 0.2); + .checkmark { + height: 14px; + width: 14px; + position: absolute; + opacity: 0; + transition: opacity 0.2s; } - &.empty-keybind { - .keybind-input { - border-color: rgba(255, 82, 82, 0.298); - } + p { + color: $text2; } } +.keybind-input { + width: min-content; + white-space: nowrap; + padding: 6px; + border: 1px solid $divider; + color: $text2; + display: flex; + border-radius: 10px; + outline: none; + gap: 4px; + + .key { + color: $text2; + font-family: SFRoundedMedium; + background-color: $divider; + padding: 2px 6px; + border-radius: 6px; + font-size: 14px; + } +} + +.keybind-input:focus { + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.empty-keybind { + border-color: rgba(255, 82, 82, 0.298); +} + +.top-bar { + width: 100%; + height: 56px; + border-bottom: 1px solid $divider; +} + .bottom-bar { height: 40px; width: calc(100vw - 2px); @@ -144,6 +211,10 @@ $mutedtext: #78756f; transition: all 0.2s; cursor: pointer; + p { + color: $text; + } + &.disabled { pointer-events: none; opacity: 0.5; diff --git a/pages/settings.vue b/pages/settings.vue index 52f84d3..d4814e0 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -1,9 +1,11 @@