ReviewOS

also looking at this

stacks/vite-plugin-tauri

feat: call custom window on tray icon event

#13
Open iamzjohn wants to merge feat/custom_window into main
43 files +5245 -1

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

bun.lockmodified+50-1
Changes to bun.lock
@@ -15,12 +15,53 @@
1515 "typescript": "^5.8.3",
1616 },
1717 },
18 "examples/tray-with-custom-tray-menu-window": {
19 "name": "custom-tray-windows-project",
20 "version": "0.0.0",
21 "dependencies": {
22 "@tauri-apps/plugin-positioner": "^2.2.0",
23 "vue": "^3.5.13",
24 },
25 "devDependencies": {
26 "@stacksjs/vite-plugin-tauri": "workspace:*",
27 "@vitejs/plugin-vue": "^5.2.3",
28 "typescript": "^5.8.3",
29 "vite": "^6.2.6",
30 },
31 },
32 "examples/tray-with-simple-menu": {
33 "name": "vite-project",
34 "version": "0.0.0",
35 "dependencies": {
36 "vue": "^3.5.13",
37 },
38 "devDependencies": {
39 "@stacksjs/vite-plugin-tauri": "workspace:*",
40 "@vitejs/plugin-vue": "^5.2.3",
41 "typescript": "^5.8.3",
42 "vite": "^6.2.6",
43 },
44 },
45 "examples/tray-with-submenus": {
46 "name": "submenu-tray",
47 "version": "0.0.0",
48 "dependencies": {
49 "vue": "^3.5.13",
50 },
51 "devDependencies": {
52 "@stacksjs/vite-plugin-tauri": "workspace:*",
53 "@vitejs/plugin-vue": "^5.2.3",
54 "typescript": "^5.8.3",
55 "vite": "^6.2.6",
56 },
57 },
1858 "packages/vite-plugin-tauri": {
1959 "name": "@stacksjs/vite-plugin-tauri",
20 "version": "0.1.0",
60 "version": "0.2.2",
2161 "dependencies": {
2262 "@tauri-apps/api": "^2.4.1",
2363 "@tauri-apps/cli": "^2.4.1",
64 "@tauri-apps/plugin-positioner": "^2.2.0",
2465 "bunfig": "^0.8.2",
2566 },
2667 "devDependencies": {
@@ -539,6 +580,8 @@
539580
540581 "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.4.1", "", { "os": "win32", "cpu": "x64" }, "sha512-60a4Ov7Jrwqz2hzDltlS7301dhSAmM9dxo+IRBD3xz7yobKrgaHXYpWvnRomYItHcDd51VaKc9292H8/eE/gsw=="],
541582
583 "@tauri-apps/plugin-positioner": ["@tauri-apps/plugin-positioner@2.2.0", "", { "dependencies": { "@tauri-apps/api": "^2.0.0" } }, "sha512-3JIWqV4U1US4nmM4PGmAHODq0ltkJ91MyANR033elKSSpX3AqKnVQnLz76xThBFHjChJrZwsXASpc2Inpu+cTg=="],
584
542585 "@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="],
543586
544587 "@types/bun": ["@types/bun@1.2.9", "", { "dependencies": { "bun-types": "1.2.9" } }, "sha512-epShhLGQYc4Bv/aceHbmBhOz1XgUnuTZgcxjxk+WXwNyDXavv5QHD1QEFV0FwbTSQtNq6g4ZcV6y0vZakTjswg=="],
@@ -875,6 +918,8 @@
875918
876919 "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
877920
921 "custom-tray-windows-project": ["custom-tray-windows-project@workspace:examples/tray-with-custom-tray-menu-window"],
922
878923 "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
879924
880925 "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="],
@@ -1683,6 +1728,8 @@
16831728
16841729 "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
16851730
1731 "submenu-tray": ["submenu-tray@workspace:examples/tray-with-submenus"],
1732
16861733 "superjson": ["superjson@2.2.2", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q=="],
16871734
16881735 "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
@@ -1803,6 +1850,8 @@
18031850
18041851 "vite-plugin-pwa": ["vite-plugin-pwa@1.0.0", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.3.0", "workbox-window": "^7.3.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-X77jo0AOd5OcxmWj3WnVti8n7Kw2tBgV1c8MCXFclrSlDV23ePzv2eTDIALXI2Qo6nJ5pZJeZAuX0AawvRfoeA=="],
18051852
1853 "vite-project": ["vite-project@workspace:examples/tray-with-simple-menu"],
1854
18061855 "vitepress": ["vitepress@1.6.3", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw=="],
18071856
18081857 "vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="],
examples/tray-with-custom-tray-menu-window/package.jsonmodified+1-1
Changes to examples/tray-with-custom-tray-menu-window/package.json
@@ -1,5 +1,5 @@
11{
2 "name": "vite-project",
2 "name": "custom-tray-windows-project",
33 "type": "module",
44 "version": "0.0.0",
55 "private": true,
examples/tray-with-custom-tray-menu-window/src-tauri/Cargo.lockmodified+34-1
Changes to examples/tray-with-custom-tray-menu-window/src-tauri/Cargo.lock
@@ -70,6 +70,7 @@ dependencies = [
7070 "serde_json",
7171 "tauri",
7272 "tauri-build",
73 "tauri-plugin-positioner",
7374]
7475
7576[[package]]
@@ -1943,7 +1944,7 @@ version = "0.7.3"
19431944source = "registry+https://github.com/rust-lang/crates.io-index"
19441945checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
19451946dependencies = [
1946 "proc-macro-crate 1.3.1",
1947 "proc-macro-crate 2.0.0",
19471948 "proc-macro2",
19481949 "quote",
19491950 "syn 2.0.91",
@@ -3319,6 +3320,38 @@ dependencies = [
33193320 "tauri-utils",
33203321]
33213322
3323[[package]]
3324name = "tauri-plugin"
3325version = "2.1.1"
3326source = "registry+https://github.com/rust-lang/crates.io-index"
3327checksum = "a4190775d6ff73fe66d9af44c012739a2659720efd9c0e1e56a918678038699d"
3328dependencies = [
3329 "anyhow",
3330 "glob",
3331 "plist",
3332 "schemars",
3333 "serde",
3334 "serde_json",
3335 "tauri-utils",
3336 "toml 0.8.20",
3337 "walkdir",
3338]
3339
3340[[package]]
3341name = "tauri-plugin-positioner"
3342version = "2.2.0"
3343source = "registry+https://github.com/rust-lang/crates.io-index"
3344checksum = "8c95b371d489bee3d1be5e5bd1538080ad408317fcc2d8546d24b290249f7bb5"
3345dependencies = [
3346 "log",
3347 "serde",
3348 "serde_json",
3349 "serde_repr",
3350 "tauri",
3351 "tauri-plugin",
3352 "thiserror 2.0.9",
3353]
3354
33223355[[package]]
33233356name = "tauri-runtime"
33243357version = "2.5.1"
examples/tray-with-custom-tray-menu-window/src-tauri/Cargo.tomlmodified+6-1
Changes to examples/tray-with-custom-tray-menu-window/src-tauri/Cargo.toml
@@ -19,11 +19,16 @@ serde_json = "1.0.140"
1919serde = { version = "1.0.219", features = [ "derive" ] }
2020tauri = { version = "2.4.1", features = [
2121 "tray-icon",
22 "image-png"
22 "image-png",
23 "unstable"
2324] }
25tauri-plugin-positioner = { version = "2.0.0", features = [ "tray-icon" ] }
2426
2527[features]
2628# this feature is used for production builds or when `devPath` points to the filesystem
2729# DO NOT remove this
2830custom-protocol = [ "tauri/custom-protocol" ]
2931tray-icon = [ ]
32
33[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
34tauri-plugin-positioner = "2"
examples/tray-with-custom-tray-menu-window/src/tray.jsmodified+62-47
Changes to examples/tray-with-custom-tray-menu-window/src/tray.js
@@ -3,6 +3,7 @@ import { defaultWindowIcon } from '@tauri-apps/api/app'
33import { TrayIcon } from '@tauri-apps/api/tray'
44import { Webview } from '@tauri-apps/api/webview'
55import { Window } from '@tauri-apps/api/window'
6// import {moveWindow, handleIconState, Position} from '@tauri-apps/plugin-positioner'
67
78/**
89 * Initialize the system tray icon and menu
@@ -11,8 +12,18 @@ export async function initTray() {
1112 try {
1213 // eslint-disable-next-line no-console
1314 console.log('Initializing system tray...')
14
1515 const appWindow = window.getCurrentWindow()
16 const trayWindow = createTrayCustomWindow()
17
18 const action = async (event) => {
19 // await handleIconState(event)
20
21 if (event.type === 'Click') {
22 // eslint-disable-next-line no-console
23 console.log('Tray icon clicked')
24 trayWindow.show()
25 }
26 }
1627
1728 // Create the tray icon with minimal options
1829 const trayIcon = await TrayIcon.new({
@@ -20,52 +31,7 @@ export async function initTray() {
2031 icon: await defaultWindowIcon(),
2132 tooltip: 'Tauri Example App',
2233 iconAsTemplate: true,
23 })
24
25 const trayKey = 'tray-window'
26 const customTrayWindow = new Window(trayKey, {
27 // parent: appWindow,
28 // center: true,
29 focus: true,
30 decorations: false,
31 resizable: false,
32 height: 300,
33 width: 400,
34 skipTaskbar: true,
35 })
36
37 customTrayWindow.once('tauri://created', () => {
38 // The window was created successfully
39 // eslint-disable-next-line no-console
40 console.log('Custom tray window created successfully')
41
42 const webview = new Webview(customTrayWindow, trayKey, {
43 url: '../index.html',
44 height: 300,
45 width: 400,
46 x: 0,
47 y: 0,
48 devtools: true,
49 })
50
51 webview.once('tauri://created', () => {
52 // The webview was created successfully
53 // eslint-disable-next-line no-console
54 console.log('Webview created successfully')
55 customTrayWindow.show()
56 webview.show()
57 })
58 webview.once('tauri://error', (e) => {
59 // The webview encountered an error
60
61 console.error('Webview error:', e)
62 })
63 })
64
65 customTrayWindow.once('tauri://error', (e) => {
66 // The window encountered an error
67
68 console.error('Custom tray window error:', e)
34 action,
6935 })
7036
7137 // eslint-disable-next-line no-console
@@ -86,3 +52,52 @@ export async function initTray() {
8652 throw error
8753 }
8854}
55
56function createTrayCustomWindow(url = '../index.html') {
57 const trayKey = 'tray-window'
58 const customTrayWindow = new Window(trayKey, {
59 focus: true,
60 decorations: false,
61 resizable: false,
62 height: 300,
63 width: 400,
64 skipTaskbar: true,
65 visible: false,
66 })
67
68 customTrayWindow.once('tauri://created', () => {
69 // The window was created successfully
70 // eslint-disable-next-line no-console
71 console.log('Custom tray window created successfully')
72
73 const webview = new Webview(customTrayWindow, trayKey, {
74 // url: 'https://github.com/tauri-apps/tauri',
75 url,
76 height: 300,
77 width: 400,
78 x: 0,
79 y: 0,
80 })
81
82 webview.once('tauri://created', () => {
83 // The webview was created successfully
84 // eslint-disable-next-line no-console
85 console.log('Webview created successfully')
86 // customTrayWindow.show()
87 // webview.show()
88 })
89 webview.once('tauri://error', (e) => {
90 // The webview encountered an error
91
92 console.error('Webview error:', e)
93 })
94 })
95
96 customTrayWindow.once('tauri://error', (e) => {
97 // The window encountered an error
98
99 console.error('Custom tray window error:', e)
100 })
101
102 return customTrayWindow
103}
package.jsonmodified+1-0
Changes to package.json
@@ -51,6 +51,7 @@
5151 },
5252 "workspaces": [
5353 "example/*",
54 "examples/*",
5455 "packages/*"
5556 ]
5657}
packages/vite-plugin-tauri/package.jsonmodified+1-0
Changes to packages/vite-plugin-tauri/package.json
@@ -52,6 +52,7 @@
5252 "dependencies": {
5353 "@tauri-apps/api": "^2.4.1",
5454 "@tauri-apps/cli": "^2.4.1",
55 "@tauri-apps/plugin-positioner": "^2.2.0",
5556 "bunfig": "^0.8.2"
5657 },
5758 "devDependencies": {
packages/vite-plugin-tauri/src/tauri.tsmodified+6-0
Changes to packages/vite-plugin-tauri/src/tauri.ts
@@ -185,6 +185,9 @@ export function tauri(config?: TauriConfig): PluginOption {
185185 'core:webview:allow-create-webview-window',
186186 'core:window:allow-hide',
187187 'core:window:allow-create',
188 'positioner:default',
189 'core:window:allow-show',
190 'core:webview:allow-webview-show',
188191 ],
189192 },
190193 ],
@@ -270,6 +273,9 @@ export function tauri(config?: TauriConfig): PluginOption {
270273 'core:webview:allow-create-webview-window',
271274 'core:window:allow-hide',
272275 'core:window:allow-create',
276 'positioner:default',
277 'core:window:allow-show',
278 'core:webview:allow-webview-show',
273279 ],
274280 },
275281 ],