feat(stage-tamagotchi): support detached devtools window with params
This commit is contained in:
@@ -139,7 +139,7 @@ app.whenReady().then(async () => {
|
||||
// BeatSync will create a background window to capture and process audio.
|
||||
const beatSync = injeca.provide('windows:beat-sync', () => setupBeatSync())
|
||||
|
||||
const devtoolsMarkdownStressWindow = injeca.provide('windows:devtools:markdown-stress', () => setupDevtoolsWindow())
|
||||
const devtoolsWindow = injeca.provide('windows:devtools', () => setupDevtoolsWindow())
|
||||
|
||||
const onboardingWindowManager = injeca.provide('windows:onboarding', {
|
||||
dependsOn: { serverChannel, i18n, windowAuthManager },
|
||||
@@ -167,7 +167,7 @@ app.whenReady().then(async () => {
|
||||
})
|
||||
|
||||
const settingsWindow = injeca.provide('windows:settings', {
|
||||
dependsOn: { widgetsManager, beatSync, autoUpdater, devtoolsMarkdownStressWindow, serverChannel, mcpStdioManager, i18n, windowAuthManager },
|
||||
dependsOn: { widgetsManager, beatSync, autoUpdater, devtoolsWindow, serverChannel, mcpStdioManager, i18n, windowAuthManager },
|
||||
build: async ({ dependsOn }) => setupSettingsWindowReusableFunc(dependsOn),
|
||||
})
|
||||
|
||||
|
||||
@@ -7,54 +7,74 @@ import icon from '../../../../resources/icon.png?asset'
|
||||
import { baseUrl, getElectronMainDirname, load, withHashRoute } from '../../libs/electron/location'
|
||||
import { createReusableWindow } from '../../libs/electron/window-manager'
|
||||
|
||||
export interface OpenDevtoolsWindowParams extends Partial<Electron.Rectangle> {
|
||||
key: string
|
||||
route?: string
|
||||
}
|
||||
|
||||
export interface DevtoolsWindowManager {
|
||||
openWindow: (route?: string) => Promise<BrowserWindow>
|
||||
getWindow: () => Promise<BrowserWindow>
|
||||
openWindow: (params: OpenDevtoolsWindowParams) => Promise<BrowserWindow>
|
||||
}
|
||||
|
||||
export function setupDevtoolsWindow(): DevtoolsWindowManager {
|
||||
const rendererBase = baseUrl(resolve(getElectronMainDirname(), '..', 'renderer'))
|
||||
const defaultRoute = '/devtools/markdown-stress'
|
||||
let currentRoute = defaultRoute
|
||||
const defaultRoute = '/devtools'
|
||||
const reusableWindows = new Map<string, ReturnType<typeof createReusableWindow>>()
|
||||
|
||||
const reusable = createReusableWindow(async () => {
|
||||
const window = new BrowserWindow({
|
||||
title: 'Devtools',
|
||||
width: 1020,
|
||||
height: 720,
|
||||
minWidth: 640,
|
||||
minHeight: 480,
|
||||
show: false,
|
||||
icon,
|
||||
webPreferences: {
|
||||
preload: join(getElectronMainDirname(), '../preload/index.mjs'),
|
||||
// Preload exposes Electron APIs and needs Node access.
|
||||
sandbox: false,
|
||||
},
|
||||
function getReusableForKey(key: string, route: string) {
|
||||
const existing = reusableWindows.get(key)
|
||||
if (existing)
|
||||
return existing
|
||||
|
||||
const reusable = createReusableWindow(async () => {
|
||||
const window = new BrowserWindow({
|
||||
title: 'Devtools',
|
||||
width: 1020,
|
||||
height: 720,
|
||||
minWidth: 640,
|
||||
minHeight: 480,
|
||||
show: false,
|
||||
icon,
|
||||
webPreferences: {
|
||||
preload: join(getElectronMainDirname(), '../preload/index.mjs'),
|
||||
// Preload exposes Electron APIs and needs Node access.
|
||||
sandbox: false,
|
||||
},
|
||||
})
|
||||
|
||||
window.on('ready-to-show', () => window.show())
|
||||
window.on('closed', () => {
|
||||
if (reusableWindows.get(key) === reusable)
|
||||
reusableWindows.delete(key)
|
||||
})
|
||||
window.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
|
||||
await load(window, withHashRoute(rendererBase, route))
|
||||
return window
|
||||
})
|
||||
|
||||
window.on('ready-to-show', () => window.show())
|
||||
window.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
reusableWindows.set(key, reusable)
|
||||
return reusable
|
||||
}
|
||||
|
||||
await load(window, withHashRoute(rendererBase, currentRoute))
|
||||
return window
|
||||
})
|
||||
async function openWindow(params: OpenDevtoolsWindowParams) {
|
||||
const targetRoute = params.route ?? defaultRoute
|
||||
const window = await getReusableForKey(params.key, targetRoute).getWindow()
|
||||
|
||||
async function openWindow(route?: string) {
|
||||
if (route)
|
||||
currentRoute = route
|
||||
|
||||
const window = await reusable.getWindow()
|
||||
const targetRoute = route ?? currentRoute
|
||||
const url = withHashRoute(rendererBase, targetRoute)
|
||||
|
||||
// If the route changes while the window is open, reload to that route.
|
||||
const currentUrl = window.webContents.getURL()
|
||||
if (!currentUrl.includes(`#${targetRoute}`)) {
|
||||
await load(window, url)
|
||||
if (params && (params.width !== undefined || params.height !== undefined || params.x !== undefined || params.y !== undefined)) {
|
||||
const bounds: Partial<Electron.Rectangle> = {}
|
||||
if (params.width !== undefined)
|
||||
bounds.width = params.width
|
||||
if (params.height !== undefined)
|
||||
bounds.height = params.height
|
||||
if (params.x !== undefined)
|
||||
bounds.x = params.x
|
||||
if (params.y !== undefined)
|
||||
bounds.y = params.y
|
||||
window.setBounds(bounds)
|
||||
}
|
||||
|
||||
return window
|
||||
@@ -62,6 +82,5 @@ export function setupDevtoolsWindow(): DevtoolsWindowManager {
|
||||
|
||||
return {
|
||||
openWindow,
|
||||
getWindow: reusable.getWindow,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface SettingsWindowManager {
|
||||
export function setupSettingsWindowReusableFunc(params: {
|
||||
widgetsManager: WidgetsWindowManager
|
||||
autoUpdater: AutoUpdater
|
||||
devtoolsMarkdownStressWindow: DevtoolsWindowManager
|
||||
devtoolsWindow: DevtoolsWindowManager
|
||||
onWindowCreated?: (window: BrowserWindow) => void
|
||||
serverChannel: ServerChannel
|
||||
mcpStdioManager: McpStdioManager
|
||||
@@ -67,7 +67,7 @@ export function setupSettingsWindowReusableFunc(params: {
|
||||
settingsWindow: window,
|
||||
widgetsManager: params.widgetsManager,
|
||||
autoUpdater: params.autoUpdater,
|
||||
devtoolsMarkdownStressWindow: params.devtoolsMarkdownStressWindow,
|
||||
devtoolsWindow: params.devtoolsWindow,
|
||||
serverChannel: params.serverChannel,
|
||||
mcpStdioManager: params.mcpStdioManager,
|
||||
i18n: params.i18n,
|
||||
|
||||
@@ -23,7 +23,7 @@ export async function setupSettingsWindowInvokes(params: {
|
||||
settingsWindow: BrowserWindow
|
||||
widgetsManager: WidgetsWindowManager
|
||||
autoUpdater: AutoUpdater
|
||||
devtoolsMarkdownStressWindow: DevtoolsWindowManager
|
||||
devtoolsWindow: DevtoolsWindowManager
|
||||
serverChannel: ServerChannel
|
||||
mcpStdioManager: McpStdioManager
|
||||
i18n: I18n
|
||||
@@ -45,7 +45,7 @@ export async function setupSettingsWindowInvokes(params: {
|
||||
|
||||
defineInvokeHandler(context, electronOpenSettingsDevtools, async () => params.settingsWindow.webContents.openDevTools({ mode: 'detach' }))
|
||||
defineInvokeHandler(context, electronOpenDevtoolsWindow, async (payload) => {
|
||||
await params.devtoolsMarkdownStressWindow.openWindow(payload?.route)
|
||||
await params.devtoolsWindow.openWindow(payload)
|
||||
})
|
||||
|
||||
return context
|
||||
|
||||
@@ -113,7 +113,7 @@ const openDevtoolsWindow = useElectronEventaInvoke(electronOpenDevtoolsWindow)
|
||||
icon="i-solar:code-bold-duotone"
|
||||
:text="t('tamagotchi.settings.devtools.pages.markdown-stress.title')"
|
||||
transition="all ease-in-out duration-250"
|
||||
@click="() => openDevtoolsWindow({ route: '/devtools/markdown-stress' })"
|
||||
@click="() => openDevtoolsWindow({ key: 'markdown-stress', route: '/devtools/markdown-stress' })"
|
||||
>
|
||||
{{ t('tamagotchi.settings.devtools.pages.markdown-stress.title') }}
|
||||
</ButtonBar>
|
||||
|
||||
@@ -22,7 +22,16 @@ export const electronOpenSettings = defineInvokeEventa<void, { route?: string }>
|
||||
export const electronSettingsNavigate = defineEventa<{ route: string }>('eventa:event:electron:windows:settings:navigate')
|
||||
export const electronOpenChat = defineInvokeEventa('eventa:invoke:electron:windows:chat:open')
|
||||
export const electronOpenSettingsDevtools = defineInvokeEventa('eventa:invoke:electron:windows:settings:devtools:open')
|
||||
export const electronOpenDevtoolsWindow = defineInvokeEventa<void, { route?: string }>('eventa:invoke:electron:windows:devtools:open')
|
||||
|
||||
export interface OpenDevtoolsWindowParams {
|
||||
key: string
|
||||
route?: string
|
||||
width?: number
|
||||
height?: number
|
||||
x?: number
|
||||
y?: number
|
||||
}
|
||||
export const electronOpenDevtoolsWindow = defineInvokeEventa<void, OpenDevtoolsWindowParams>('eventa:invoke:electron:windows:devtools:open')
|
||||
|
||||
export interface ElectronServerChannelConfig {
|
||||
tlsConfig?: ServerOptions['tlsConfig'] | null
|
||||
|
||||
Reference in New Issue
Block a user