diff --git a/js/src/components/window-controls.tsx b/js/src/components/window-controls.tsx index 04e1438..5d9a4b3 100644 --- a/js/src/components/window-controls.tsx +++ b/js/src/components/window-controls.tsx @@ -1,33 +1,64 @@ +import { useEffect, useState } from "react"; +import { Copy, Minus, Square, X } from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; + export function WindowControls() { + const [isMaximized, setIsMaximized] = useState(false); + + useEffect(() => { + return window.electronWindow.onMaximizeChange(setIsMaximized); + }, []); + + const minimize = ( + + ); + + const maximize = ( + + ); + + const close = ( + + ); + + const buttons = [close, maximize, minimize]; + return ( -
- - - +
+ {buttons}
); } diff --git a/js/src/electron.d.ts b/js/src/electron.d.ts index c09ed0a..a3a1ee6 100644 --- a/js/src/electron.d.ts +++ b/js/src/electron.d.ts @@ -17,6 +17,8 @@ declare global { close: () => void; openHuddle: (data: { token: string; serverUrl: string }) => void; closeHuddle: () => void; + platform: NodeJS.Platform; + onMaximizeChange: (callback: (isMaximized: boolean) => void) => () => void; }; electronHuddle: { getScreenSources: () => Promise; diff --git a/js/src/features/layout.tsx b/js/src/features/layout.tsx index 942d1e8..7aa3d45 100644 --- a/js/src/features/layout.tsx +++ b/js/src/features/layout.tsx @@ -92,10 +92,10 @@ function TopBar() { const { data: particle } = useParticle(path); return ( -
+
- + {segments.length === 0 ? ( diff --git a/js/src/features/particles/stream-top-bar.tsx b/js/src/features/particles/stream-top-bar.tsx index bfc92a4..3dc0fb4 100644 --- a/js/src/features/particles/stream-top-bar.tsx +++ b/js/src/features/particles/stream-top-bar.tsx @@ -77,7 +77,7 @@ export function TopBar({ networkId, particle, streamParticle }: TopBarProps) { }; return ( -
+
diff --git a/js/src/features/particles/stream-view.tsx b/js/src/features/particles/stream-view.tsx index 20a1fbf..ba8f83e 100644 --- a/js/src/features/particles/stream-view.tsx +++ b/js/src/features/particles/stream-view.tsx @@ -419,7 +419,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
{/* TopBar — always visible */} -
+
diff --git a/js/src/main.ts b/js/src/main.ts index 2261477..e56453f 100644 --- a/js/src/main.ts +++ b/js/src/main.ts @@ -124,6 +124,13 @@ const createWindow = () => { }); hardenWindow(mainWindow); + mainWindow.on('maximize', () => { + mainWindow?.webContents.send('window:maximize-changed', true); + }); + mainWindow.on('unmaximize', () => { + mainWindow?.webContents.send('window:maximize-changed', false); + }); + if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL); mainWindow.webContents.openDevTools(); diff --git a/js/src/preload.ts b/js/src/preload.ts index 137a7a8..5274f02 100644 --- a/js/src/preload.ts +++ b/js/src/preload.ts @@ -9,6 +9,12 @@ contextBridge.exposeInMainWorld('electronWindow', { close: () => ipcRenderer.send('window:close'), openHuddle: (data: { token: string; serverUrl: string }) => ipcRenderer.send('window:open-huddle', data), closeHuddle: () => ipcRenderer.send('window:close-huddle'), + platform: process.platform, + onMaximizeChange: (callback: (isMaximized: boolean) => void) => { + const handler = (_event: Electron.IpcRendererEvent, value: boolean) => callback(value); + ipcRenderer.on('window:maximize-changed', handler); + return () => { ipcRenderer.removeListener('window:maximize-changed', handler); }; + }, }); contextBridge.exposeInMainWorld('electronHuddle', {