diff --git a/frontend/apps/editor3d/app/src/styles/base.css b/frontend/apps/editor3d/app/src/styles/base.css
index f30a6ccd2a..05d4cd48e8 100644
--- a/frontend/apps/editor3d/app/src/styles/base.css
+++ b/frontend/apps/editor3d/app/src/styles/base.css
@@ -46,6 +46,23 @@ body {
user-select: none;
}
+/* Tauri custom titlebar drag regions */
+[data-tauri-drag-region] {
+ -webkit-app-region: drag;
+ app-region: drag;
+}
+
+.tauri-no-drag,
+[data-tauri-drag-region] .no-drag,
+[data-tauri-drag-region] button,
+[data-tauri-drag-region] a,
+[data-tauri-drag-region] input,
+[data-tauri-drag-region] textarea,
+[data-tauri-drag-region] select {
+ -webkit-app-region: no-drag;
+ app-region: no-drag;
+}
+
img {
user-select: none;
pointer-events: none;
diff --git a/frontend/libs/components/menu-icon-selector/src/lib/menu-icon-selector.tsx b/frontend/libs/components/menu-icon-selector/src/lib/menu-icon-selector.tsx
index b02d4f82a1..227013d0a1 100644
--- a/frontend/libs/components/menu-icon-selector/src/lib/menu-icon-selector.tsx
+++ b/frontend/libs/components/menu-icon-selector/src/lib/menu-icon-selector.tsx
@@ -84,7 +84,7 @@ export const MenuIconSelector: React.FC
= ({
>
setHoveredIndex(-1)}
>
diff --git a/frontend/libs/components/provider-setup-modal/tsconfig.json b/frontend/libs/components/provider-setup-modal/tsconfig.json
index 12b1e10ef8..b2d0f690d2 100644
--- a/frontend/libs/components/provider-setup-modal/tsconfig.json
+++ b/frontend/libs/components/provider-setup-modal/tsconfig.json
@@ -3,19 +3,16 @@
"include": [],
"references": [
{
- "path": "../button"
- },
- {
- "path": "../modal"
+ "path": "../../common"
},
{
"path": "../../tauri-events"
},
{
- "path": "../../tauri-api"
+ "path": "../button"
},
{
- "path": "../../common"
+ "path": "../modal"
},
{
"path": "./tsconfig.lib.json"
diff --git a/frontend/libs/components/provider-setup-modal/tsconfig.lib.json b/frontend/libs/components/provider-setup-modal/tsconfig.lib.json
index 4b429f449b..f03ada54f3 100644
--- a/frontend/libs/components/provider-setup-modal/tsconfig.lib.json
+++ b/frontend/libs/components/provider-setup-modal/tsconfig.lib.json
@@ -44,19 +44,16 @@
],
"references": [
{
- "path": "../button/tsconfig.lib.json"
- },
- {
- "path": "../modal/tsconfig.lib.json"
+ "path": "../../common/tsconfig.lib.json"
},
{
"path": "../../tauri-events/tsconfig.lib.json"
},
{
- "path": "../../tauri-api/tsconfig.lib.json"
+ "path": "../button/tsconfig.lib.json"
},
{
- "path": "../../common/tsconfig.lib.json"
+ "path": "../modal/tsconfig.lib.json"
}
]
}
diff --git a/frontend/libs/tauri-events/tsconfig.json b/frontend/libs/tauri-events/tsconfig.json
index 8c5fc025ff..11c74cf946 100644
--- a/frontend/libs/tauri-events/tsconfig.json
+++ b/frontend/libs/tauri-events/tsconfig.json
@@ -2,6 +2,18 @@
"files": [],
"include": [],
"references": [
+ {
+ "path": "../components/toaster"
+ },
+ {
+ "path": "../tauri-api"
+ },
+ {
+ "path": "../soundboard"
+ },
+ {
+ "path": "../common"
+ },
{
"path": "./tsconfig.lib.json"
},
diff --git a/frontend/libs/tauri-events/tsconfig.lib.json b/frontend/libs/tauri-events/tsconfig.lib.json
index ea31c66850..cdcccc7004 100644
--- a/frontend/libs/tauri-events/tsconfig.lib.json
+++ b/frontend/libs/tauri-events/tsconfig.lib.json
@@ -41,5 +41,19 @@
"src/**/*.jsx",
"src/**/*.ts",
"src/**/*.tsx"
+ ],
+ "references": [
+ {
+ "path": "../components/toaster/tsconfig.lib.json"
+ },
+ {
+ "path": "../tauri-api/tsconfig.lib.json"
+ },
+ {
+ "path": "../soundboard/tsconfig.lib.json"
+ },
+ {
+ "path": "../common/tsconfig.lib.json"
+ }
]
}
diff --git a/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx b/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx
index 8354df73dd..bf139b8d4b 100644
--- a/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx
+++ b/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx
@@ -1,3 +1,11 @@
-export * from './api';
-export { FetchProxy } from './FetchProxy';
-export { IsDesktopApp } from './IsDesktopApp';
+export * from "./api";
+export { FetchProxy } from "./FetchProxy";
+export { IsDesktopApp } from "./IsDesktopApp";
+export {
+ useTauriWindowControls,
+ minimizeCurrentWindow,
+ toggleMaximizeCurrentWindow,
+ closeCurrentWindow,
+ isCurrentWindowMaximized,
+} from "./useWindowControls";
+export { useTauriPlatform } from "./usePlatform";
diff --git a/frontend/libs/tauri-utils/src/lib/usePlatform.ts b/frontend/libs/tauri-utils/src/lib/usePlatform.ts
new file mode 100644
index 0000000000..d6716e6e51
--- /dev/null
+++ b/frontend/libs/tauri-utils/src/lib/usePlatform.ts
@@ -0,0 +1,22 @@
+import { useEffect, useState } from "react";
+import { IsDesktopApp } from "./IsDesktopApp";
+
+export type TauriPlatform = "windows" | "macos" | "linux";
+
+export function useTauriPlatform(): TauriPlatform | undefined {
+ const [platform, setPlatform] = useState(
+ undefined
+ );
+
+ useEffect(() => {
+ if (!IsDesktopApp()) return;
+ if (typeof navigator !== "undefined") {
+ const ua = navigator.userAgent || "";
+ if (/Macintosh|Mac OS X/i.test(ua)) setPlatform("macos");
+ else if (/Windows/i.test(ua)) setPlatform("windows");
+ else setPlatform("linux");
+ }
+ }, []);
+
+ return platform;
+}
diff --git a/frontend/libs/tauri-utils/src/lib/useWindowControls.ts b/frontend/libs/tauri-utils/src/lib/useWindowControls.ts
new file mode 100644
index 0000000000..8c2da336d9
--- /dev/null
+++ b/frontend/libs/tauri-utils/src/lib/useWindowControls.ts
@@ -0,0 +1,94 @@
+import { useEffect, useState, useCallback } from "react";
+import { IsDesktopApp } from "./IsDesktopApp";
+
+async function getCurrentWindowSafe() {
+ const { getCurrentWindow } = await import("@tauri-apps/api/window");
+ return getCurrentWindow();
+}
+
+export function useTauriWindowControls() {
+ const isDesktop = IsDesktopApp();
+ const [isMaximized, setIsMaximized] = useState(false);
+
+ useEffect(() => {
+ if (!isDesktop) return;
+ let unlistenMax: (() => void) | undefined;
+ let unlistenUnmax: (() => void) | undefined;
+ let unlistenResize: (() => void) | undefined;
+
+ (async () => {
+ try {
+ const win = await getCurrentWindowSafe();
+ setIsMaximized(await win.isMaximized());
+ } catch (err) {
+ // ignore
+ }
+
+ try {
+ const { listen } = await import("@tauri-apps/api/event");
+ unlistenMax = await listen("tauri://maximize", () =>
+ setIsMaximized(true)
+ );
+ unlistenUnmax = await listen("tauri://unmaximize", () =>
+ setIsMaximized(false)
+ );
+ unlistenResize = await listen("tauri://resize", async () => {
+ try {
+ const win = await getCurrentWindowSafe();
+ setIsMaximized(await win.isMaximized());
+ } catch (err) {
+ // ignore
+ }
+ });
+ } catch (err) {
+ // ignore
+ }
+ })();
+
+ return () => {
+ if (unlistenMax) unlistenMax();
+ if (unlistenUnmax) unlistenUnmax();
+ if (unlistenResize) unlistenResize();
+ };
+ }, [isDesktop]);
+
+ const minimize = useCallback(async () => {
+ if (!isDesktop) return;
+ const win = await getCurrentWindowSafe();
+ await win.minimize();
+ }, [isDesktop]);
+
+ const toggleMaximize = useCallback(async () => {
+ if (!isDesktop) return;
+ const win = await getCurrentWindowSafe();
+ await win.toggleMaximize();
+ }, [isDesktop]);
+
+ const close = useCallback(async () => {
+ if (!isDesktop) return;
+ const win = await getCurrentWindowSafe();
+ await win.close();
+ }, [isDesktop]);
+
+ return { isDesktop, isMaximized, minimize, toggleMaximize, close };
+}
+
+export async function minimizeCurrentWindow() {
+ const win = await getCurrentWindowSafe();
+ return win.minimize();
+}
+
+export async function toggleMaximizeCurrentWindow() {
+ const win = await getCurrentWindowSafe();
+ return win.toggleMaximize();
+}
+
+export async function closeCurrentWindow() {
+ const win = await getCurrentWindowSafe();
+ return win.close();
+}
+
+export async function isCurrentWindowMaximized(): Promise {
+ const win = await getCurrentWindowSafe();
+ return win.isMaximized();
+}