Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
a33e6c6a
Unverified
提交
a33e6c6a
authored
4月 29, 2025
作者:
Will Chen
提交者:
GitHub
4月 29, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Custom window controls (#46)
上级
672bd790
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
200 行增加
和
1 行删除
+200
-1
TitleBar.tsx
src/app/TitleBar.tsx
+99
-0
window_handlers.ts
src/ipc/handlers/window_handlers.ts
+53
-0
ipc_client.ts
src/ipc/ipc_client.ts
+41
-0
ipc_host.ts
src/ipc/ipc_host.ts
+2
-0
main.ts
src/main.ts
+1
-1
preload.ts
src/preload.ts
+4
-0
没有找到文件。
src/app/TitleBar.tsx
浏览文件 @
a33e6c6a
...
@@ -11,6 +11,8 @@ import { cn } from "@/lib/utils";
...
@@ -11,6 +11,8 @@ import { cn } from "@/lib/utils";
import
{
useDeepLink
}
from
"@/contexts/DeepLinkContext"
;
import
{
useDeepLink
}
from
"@/contexts/DeepLinkContext"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
DyadProSuccessDialog
}
from
"@/components/DyadProSuccessDialog"
;
import
{
DyadProSuccessDialog
}
from
"@/components/DyadProSuccessDialog"
;
import
{
useTheme
}
from
"@/contexts/ThemeContext"
;
import
{
IpcClient
}
from
"@/ipc/ipc_client"
;
export
const
TitleBar
=
()
=>
{
export
const
TitleBar
=
()
=>
{
const
[
selectedAppId
]
=
useAtom
(
selectedAppIdAtom
);
const
[
selectedAppId
]
=
useAtom
(
selectedAppIdAtom
);
...
@@ -18,6 +20,21 @@ export const TitleBar = () => {
...
@@ -18,6 +20,21 @@ export const TitleBar = () => {
const
{
navigate
}
=
useRouter
();
const
{
navigate
}
=
useRouter
();
const
{
settings
,
refreshSettings
}
=
useSettings
();
const
{
settings
,
refreshSettings
}
=
useSettings
();
const
[
isSuccessDialogOpen
,
setIsSuccessDialogOpen
]
=
useState
(
false
);
const
[
isSuccessDialogOpen
,
setIsSuccessDialogOpen
]
=
useState
(
false
);
const
[
showWindowControls
,
setShowWindowControls
]
=
useState
(
false
);
useEffect
(()
=>
{
// Check if we're running on Windows
const
checkPlatform
=
async
()
=>
{
try
{
const
platform
=
await
IpcClient
.
getInstance
().
getSystemPlatform
();
setShowWindowControls
(
platform
!==
"darwin"
);
}
catch
(
error
)
{
console
.
error
(
"Failed to get platform info:"
,
error
);
}
};
checkPlatform
();
},
[]);
const
showDyadProSuccessDialog
=
()
=>
{
const
showDyadProSuccessDialog
=
()
=>
{
setIsSuccessDialogOpen
(
true
);
setIsSuccessDialogOpen
(
true
);
...
@@ -82,6 +99,7 @@ export const TitleBar = () => {
...
@@ -82,6 +99,7 @@ export const TitleBar = () => {
{
isDyadProEnabled
?
"Dyad Pro"
:
"Dyad Pro (disabled)"
}
{
isDyadProEnabled
?
"Dyad Pro"
:
"Dyad Pro (disabled)"
}
</
Button
>
</
Button
>
)
}
)
}
{
showWindowControls
&&
<
WindowsControls
/>
}
</
div
>
</
div
>
<
DyadProSuccessDialog
<
DyadProSuccessDialog
...
@@ -91,3 +109,84 @@ export const TitleBar = () => {
...
@@ -91,3 +109,84 @@ export const TitleBar = () => {
</>
</>
);
);
};
};
function
WindowsControls
()
{
const
{
isDarkMode
}
=
useTheme
();
const
ipcClient
=
IpcClient
.
getInstance
();
const
minimizeWindow
=
()
=>
{
ipcClient
.
minimizeWindow
();
};
const
maximizeWindow
=
()
=>
{
ipcClient
.
maximizeWindow
();
};
const
closeWindow
=
()
=>
{
ipcClient
.
closeWindow
();
};
return
(
<
div
className=
"ml-auto flex no-app-region-drag"
>
<
button
className=
"w-12 h-11 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
onClick=
{
minimizeWindow
}
aria
-
label=
"Minimize"
>
<
svg
width=
"12"
height=
"1"
viewBox=
"0 0 12 1"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
rect
width=
"12"
height=
"1"
fill=
{
isDarkMode
?
"#ffffff"
:
"#000000"
}
/>
</
svg
>
</
button
>
<
button
className=
"w-12 h-11 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
onClick=
{
maximizeWindow
}
aria
-
label=
"Maximize"
>
<
svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
rect
x=
"0.5"
y=
"0.5"
width=
"11"
height=
"11"
stroke=
{
isDarkMode
?
"#ffffff"
:
"#000000"
}
/>
</
svg
>
</
button
>
<
button
className=
"w-12 h-11 flex items-center justify-center hover:bg-red-500 transition-colors"
onClick=
{
closeWindow
}
aria
-
label=
"Close"
>
<
svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
d=
"M1 1L11 11M1 11L11 1"
stroke=
{
isDarkMode
?
"#ffffff"
:
"#000000"
}
strokeWidth=
"1.5"
/>
</
svg
>
</
button
>
</
div
>
);
}
src/ipc/handlers/window_handlers.ts
0 → 100644
浏览文件 @
a33e6c6a
import
{
BrowserWindow
,
ipcMain
}
from
"electron"
;
import
log
from
"electron-log"
;
import
{
platform
}
from
"os"
;
const
logger
=
log
.
scope
(
"window-handlers"
);
// Handler for minimizing the window
const
handleMinimize
=
(
event
:
Electron
.
IpcMainInvokeEvent
)
=>
{
const
window
=
BrowserWindow
.
fromWebContents
(
event
.
sender
);
if
(
!
window
)
{
logger
.
error
(
"Failed to get BrowserWindow instance for minimize command"
);
return
;
}
window
.
minimize
();
};
// Handler for maximizing/restoring the window
const
handleMaximize
=
(
event
:
Electron
.
IpcMainInvokeEvent
)
=>
{
const
window
=
BrowserWindow
.
fromWebContents
(
event
.
sender
);
if
(
!
window
)
{
logger
.
error
(
"Failed to get BrowserWindow instance for maximize command"
);
return
;
}
if
(
window
.
isMaximized
())
{
window
.
restore
();
}
else
{
window
.
maximize
();
}
};
// Handler for closing the window
const
handleClose
=
(
event
:
Electron
.
IpcMainInvokeEvent
)
=>
{
const
window
=
BrowserWindow
.
fromWebContents
(
event
.
sender
);
if
(
!
window
)
{
logger
.
error
(
"Failed to get BrowserWindow instance for close command"
);
return
;
}
window
.
close
();
};
// Handler to get the current system platform
const
handleGetSystemPlatform
=
()
=>
{
return
platform
();
};
export
function
registerWindowHandlers
()
{
logger
.
debug
(
"Registering window control handlers"
);
ipcMain
.
handle
(
"window:minimize"
,
handleMinimize
);
ipcMain
.
handle
(
"window:maximize"
,
handleMaximize
);
ipcMain
.
handle
(
"window:close"
,
handleClose
);
ipcMain
.
handle
(
"window:get-platform"
,
handleGetSystemPlatform
);
}
src/ipc/ipc_client.ts
浏览文件 @
a33e6c6a
...
@@ -776,4 +776,45 @@ export class IpcClient {
...
@@ -776,4 +776,45 @@ export class IpcClient {
throw
error
;
throw
error
;
}
}
}
}
// Window control methods
public
async
minimizeWindow
():
Promise
<
void
>
{
try
{
await
this
.
ipcRenderer
.
invoke
(
"window:minimize"
);
}
catch
(
error
)
{
showError
(
error
);
throw
error
;
}
}
public
async
maximizeWindow
():
Promise
<
void
>
{
try
{
await
this
.
ipcRenderer
.
invoke
(
"window:maximize"
);
}
catch
(
error
)
{
showError
(
error
);
throw
error
;
}
}
public
async
closeWindow
():
Promise
<
void
>
{
try
{
await
this
.
ipcRenderer
.
invoke
(
"window:close"
);
}
catch
(
error
)
{
showError
(
error
);
throw
error
;
}
}
// Get system platform (win32, darwin, linux)
public
async
getSystemPlatform
():
Promise
<
string
>
{
try
{
const
platform
=
await
this
.
ipcRenderer
.
invoke
(
"window:get-platform"
);
return
platform
;
}
catch
(
error
)
{
showError
(
error
);
throw
error
;
}
}
// --- End window control methods ---
}
}
src/ipc/ipc_host.ts
浏览文件 @
a33e6c6a
...
@@ -11,6 +11,7 @@ import { registerDebugHandlers } from "./handlers/debug_handlers";
...
@@ -11,6 +11,7 @@ import { registerDebugHandlers } from "./handlers/debug_handlers";
import
{
registerSupabaseHandlers
}
from
"./handlers/supabase_handlers"
;
import
{
registerSupabaseHandlers
}
from
"./handlers/supabase_handlers"
;
import
{
registerLocalModelHandlers
}
from
"./handlers/local_model_handlers"
;
import
{
registerLocalModelHandlers
}
from
"./handlers/local_model_handlers"
;
import
{
registerTokenCountHandlers
}
from
"./handlers/token_count_handlers"
;
import
{
registerTokenCountHandlers
}
from
"./handlers/token_count_handlers"
;
import
{
registerWindowHandlers
}
from
"./handlers/window_handlers"
;
export
function
registerIpcHandlers
()
{
export
function
registerIpcHandlers
()
{
// Register all IPC handlers by category
// Register all IPC handlers by category
...
@@ -27,4 +28,5 @@ export function registerIpcHandlers() {
...
@@ -27,4 +28,5 @@ export function registerIpcHandlers() {
registerSupabaseHandlers
();
registerSupabaseHandlers
();
registerLocalModelHandlers
();
registerLocalModelHandlers
();
registerTokenCountHandlers
();
registerTokenCountHandlers
();
registerWindowHandlers
();
}
}
src/main.ts
浏览文件 @
a33e6c6a
...
@@ -96,7 +96,7 @@ const createWindow = () => {
...
@@ -96,7 +96,7 @@ const createWindow = () => {
width
:
process
.
env
.
NODE_ENV
===
"development"
?
1280
:
960
,
width
:
process
.
env
.
NODE_ENV
===
"development"
?
1280
:
960
,
height
:
700
,
height
:
700
,
titleBarStyle
:
"hidden"
,
titleBarStyle
:
"hidden"
,
titleBarOverlay
:
tru
e
,
titleBarOverlay
:
fals
e
,
trafficLightPosition
:
{
trafficLightPosition
:
{
x
:
10
,
x
:
10
,
y
:
8
,
y
:
8
,
...
...
src/preload.ts
浏览文件 @
a33e6c6a
...
@@ -48,6 +48,10 @@ const validInvokeChannels = [
...
@@ -48,6 +48,10 @@ const validInvokeChannels = [
"supabase:set-app-project"
,
"supabase:set-app-project"
,
"supabase:unset-app-project"
,
"supabase:unset-app-project"
,
"local-models:list"
,
"local-models:list"
,
"window:minimize"
,
"window:maximize"
,
"window:close"
,
"window:get-platform"
,
]
as
const
;
]
as
const
;
// Add valid receive channels
// Add valid receive channels
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论