Skip to content

Commit 1890896

Browse files
committed
feat(electron): add remote dev mode, enhance navigation handling, and update Electron UI styles
- Introduced `--remote` flag for Electron dev mode to load external URLs. - Added navigation guards to restrict navigation and external URL handling. - Updated Electron styles for title bar spacing and transparency adjustments. - Removed unused assets (`icon.svg`, `logo.svg`) and optimized workspace connection logic.
1 parent 7443ed6 commit 1890896

10 files changed

Lines changed: 96 additions & 60 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"db:migrate": "bun run --cwd packages/api db:migrate",
1818
"db:studio": "bun run --cwd packages/api db:studio",
1919
"electron:dev": "bun run build:ui && cd packages/electron && npm run dev",
20+
"electron:dev:remote": "cd packages/electron && npm run dev:remote",
2021
"electron:build": "bun run build:ui && cd packages/electron && npm run dist"
2122
},
2223
"devDependencies": {

packages/electron/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"build:main": "tsc -p tsconfig.json",
88
"start": "npm run build:main && electron dist/main.js",
99
"dev": "npm run build:main && electron dist/main.js --dev",
10+
"dev:remote": "npm run build:main && electron dist/main.js --dev --remote",
1011
"dist": "npm run build:main && electron-builder"
1112
},
1213
"dependencies": {

packages/electron/src/main.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { app, BrowserWindow, ipcMain, net } from 'electron';
1+
import { app, BrowserWindow, ipcMain, net, shell } from 'electron';
22
import path from 'path';
33
import { getStore } from './store';
44

@@ -40,14 +40,37 @@ async function createWindow() {
4040

4141
// Load the UI
4242
const isDev = process.argv.includes('--dev');
43+
const isRemote = process.argv.includes('--remote');
44+
const devUrl = isRemote ? 'https://ra.grasco.dev' : 'http://localhost:5173';
45+
const allowedOrigin = isDev ? new URL(devUrl).origin : 'file://';
46+
4347
if (isDev) {
44-
mainWindow.loadURL('http://localhost:5173');
45-
mainWindow.webContents.openDevTools();
48+
mainWindow.loadURL(devUrl);
49+
if (!isRemote) mainWindow.webContents.openDevTools();
4650
} else {
4751
const uiPath = path.join(process.resourcesPath, 'ui', 'index.html');
4852
mainWindow.loadFile(uiPath);
4953
}
5054

55+
// Open external URLs in default browser, only allow the app origin
56+
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
57+
try {
58+
if (new URL(url).origin !== allowedOrigin) {
59+
shell.openExternal(url);
60+
}
61+
} catch {}
62+
return { action: 'deny' };
63+
});
64+
65+
mainWindow.webContents.on('will-navigate', (event, url) => {
66+
try {
67+
if (new URL(url).origin !== allowedOrigin) {
68+
event.preventDefault();
69+
shell.openExternal(url);
70+
}
71+
} catch {}
72+
});
73+
5174
mainWindow.on('closed', () => {
5275
mainWindow = null;
5376
});

packages/ui/public/icon.svg

Lines changed: 0 additions & 24 deletions
This file was deleted.

packages/ui/public/logo.png

115 KB
Loading

packages/ui/public/logo.svg

Lines changed: 0 additions & 24 deletions
This file was deleted.

packages/ui/src/components/AppSidebar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ export function AppSidebar({ data, isLoading, onClose }: AppSidebarProps) {
421421

422422
return (
423423
<div className="flex flex-col h-full bg-card text-foreground">
424+
{/* Electron: traffic light spacer + drag region */}
425+
<div className="hidden electron-titlebar h-[38px] shrink-0 app-drag" />
424426
{/* Top nav tabs with sliding pill */}
425427
<div className="flex items-center gap-0.5 px-2 pt-3 pb-2 shrink-0">
426428
{(['workspaces', 'tasks'] as const).map((tab) => (

packages/ui/src/index.css

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,10 @@
221221

222222
/* Electron: frosted glass card */
223223
.frosted-card {
224-
background: hsla(var(--card), 0.6);
224+
background: hsl(var(--card) / 0.6);
225225
backdrop-filter: blur(40px) saturate(1.8);
226226
-webkit-backdrop-filter: blur(40px) saturate(1.8);
227-
border: 1px solid hsla(var(--border), 0.3);
227+
border: 1px solid hsl(var(--border) / 0.3);
228228
box-shadow:
229229
0 8px 32px rgba(0, 0, 0, 0.3),
230230
inset 0 1px 0 hsla(0, 0%, 100%, 0.05);
@@ -238,10 +238,28 @@
238238
-webkit-app-region: no-drag;
239239
}
240240

241-
/* Electron: transparent background for acrylic */
242-
.electron-app body {
241+
/* Electron: transparent backgrounds for acrylic/vibrancy */
242+
.electron-app,
243+
.electron-app body,
244+
.electron-app body.bg-background,
245+
.electron-app #root,
246+
.electron-app #root > * {
243247
background: transparent !important;
248+
background-color: transparent !important;
244249
}
245-
.electron-app .min-h-screen {
246-
background: transparent;
250+
251+
/* Electron: translucent surfaces */
252+
.electron-app .bg-background:not(body):not(#root > *) {
253+
background-color: hsl(var(--background) / 0.6) !important;
254+
}
255+
.electron-app .bg-card {
256+
background-color: hsl(var(--card) / 0.5) !important;
257+
}
258+
.electron-app .bg-background\/95 {
259+
background-color: hsl(var(--background) / 0.5) !important;
260+
}
261+
262+
/* Electron: show traffic light spacer */
263+
.electron-app .electron-titlebar {
264+
display: block !important;
247265
}

packages/ui/src/lib/api-config.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,30 @@ export const useApiConfig = create<ApiConfigState>((set) => ({
5858
}));
5959

6060
export function getApiBase(): string {
61-
return useApiConfig.getState().apiBaseUrl;
61+
const configured = useApiConfig.getState().apiBaseUrl;
62+
if (!configured) return '';
63+
// If configured URL matches the current page origin, use relative URLs
64+
// so requests go through the same origin (e.g. vite proxy in dev)
65+
try {
66+
const configuredOrigin = new URL(configured).origin;
67+
if (configuredOrigin === window.location.origin) return '';
68+
} catch {
69+
// invalid URL, return as-is
70+
}
71+
return configured;
6272
}
6373

6474
export function getWsBase(): string {
65-
return useApiConfig.getState().wsBaseUrl;
75+
const configured = useApiConfig.getState().wsBaseUrl;
76+
if (!configured) return '';
77+
// If configured WS URL matches the current page origin, use relative WS
78+
// so connections go through the same origin (e.g. vite proxy in dev)
79+
try {
80+
const configuredOrigin = new URL(configured).origin;
81+
const pageWsOrigin = window.location.origin.replace(/^http/, 'ws');
82+
if (configuredOrigin === pageWsOrigin) return '';
83+
} catch {
84+
// invalid URL, return as-is
85+
}
86+
return configured;
6687
}

packages/ui/src/pages/Login.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { Button } from '@/components/ui/Button';
55
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/Card';
66
import { Input } from '@/components/ui/Input';
77
import { useGitHubOAuthStatus } from '@/hooks/useGitHubApps';
8-
import { getApiBase } from '@/lib/api-config';
8+
import { getApiBase, useApiConfig } from '@/lib/api-config';
9+
import { isElectron, getElectronAPI } from '@/lib/electron';
910

1011
export function LoginPage() {
1112
const [email, setEmail] = useState('');
@@ -112,6 +113,23 @@ export function LoginPage() {
112113
<p className="text-center text-xs text-muted-foreground">
113114
By continuing, you agree to our terms of service and privacy policy.
114115
</p>
116+
117+
{isElectron() && (
118+
<button
119+
type="button"
120+
onClick={async () => {
121+
const electronAPI = getElectronAPI();
122+
if (electronAPI) {
123+
await electronAPI.setApiUrl('');
124+
}
125+
useApiConfig.getState().setApiUrl('');
126+
useApiConfig.setState({ isConfigured: false });
127+
}}
128+
className="w-full text-xs text-muted-foreground hover:text-foreground transition-colors"
129+
>
130+
Connect to another workspace
131+
</button>
132+
)}
115133
</CardContent>
116134
</Card>
117135
</div>

0 commit comments

Comments
 (0)