You've already forked Nano-Banana-AI-Image-Editor
新增 现在支持编译为Windows桌面端
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { cn } from './utils/cn';
|
||||
import { Header } from './components/Header';
|
||||
import { CustomTitleBar } from './components/CustomTitleBar';
|
||||
import { PromptComposer } from './components/PromptComposer';
|
||||
import { ImageCanvas } from './components/ImageCanvas';
|
||||
import { HistoryPanel } from './components/HistoryPanel';
|
||||
@@ -91,9 +91,7 @@ function AppContent() {
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-gray-50 text-gray-900 flex flex-col font-sans">
|
||||
<div className="card card-lg rounded-none">
|
||||
<Header />
|
||||
</div>
|
||||
<CustomTitleBar />
|
||||
|
||||
<div className="flex-1 flex overflow-hidden p-4 gap-4 relative">
|
||||
<div className={cn("flex-shrink-0 transition-all duration-300 ease-in-out overflow-hidden", showPromptPanel ? "w-72" : "w-8")}>
|
||||
|
||||
107
src/components/CustomTitleBar.tsx
Normal file
107
src/components/CustomTitleBar.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button } from './ui/Button';
|
||||
import { HelpCircle, Minus, Square, X } from 'lucide-react';
|
||||
import { InfoModal } from './InfoModal';
|
||||
|
||||
export const CustomTitleBar: React.FC = () => {
|
||||
const [showInfoModal, setShowInfoModal] = useState(false);
|
||||
const [isMaximized, setIsMaximized] = useState(false);
|
||||
|
||||
// 检查窗口是否最大化
|
||||
useEffect(() => {
|
||||
const checkMaximized = () => {
|
||||
if (window.electron && window.electron.isMaximized) {
|
||||
window.electron.isMaximized().then(setIsMaximized);
|
||||
}
|
||||
};
|
||||
|
||||
checkMaximized();
|
||||
|
||||
// 监听窗口状态变化
|
||||
const handleResize = () => {
|
||||
checkMaximized();
|
||||
};
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, []);
|
||||
|
||||
const minimizeWindow = () => {
|
||||
if (window.electron && window.electron.minimize) {
|
||||
window.electron.minimize();
|
||||
}
|
||||
};
|
||||
|
||||
const maximizeWindow = () => {
|
||||
if (window.electron && window.electron.maximize) {
|
||||
window.electron.maximize();
|
||||
}
|
||||
};
|
||||
|
||||
const closeWindow = () => {
|
||||
if (window.electron && window.electron.close) {
|
||||
window.electron.close();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="h-12 bg-white flex items-center justify-between px-3 rounded-t-xl border-b border-gray-200 draggable">
|
||||
<div className="flex items-center space-x-2 non-draggable">
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-yellow-50">
|
||||
{/* 使用应用的主要图标 */}
|
||||
<img src="./favicon.svg" alt="App Icon" className="w-6 h-6" />
|
||||
</div>
|
||||
<h1 className="text-base font-medium text-gray-800 hidden sm:block">
|
||||
Nano Banana AI 图像编辑器
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-1 non-draggable">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setShowInfoModal(true)}
|
||||
className="h-7 w-7 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full card non-draggable"
|
||||
>
|
||||
<HelpCircle className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
{/* 窗口控制按钮 - 仅在 Electron 环境中显示 */}
|
||||
{window.electron && (
|
||||
<>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={minimizeWindow}
|
||||
className="h-7 w-7 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full card non-draggable"
|
||||
>
|
||||
<Minus className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={maximizeWindow}
|
||||
className="h-7 w-7 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-full card non-draggable"
|
||||
>
|
||||
<Square className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={closeWindow}
|
||||
className="h-7 w-7 text-gray-500 hover:text-gray-700 hover:bg-red-100 rounded-full card non-draggable"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<InfoModal open={showInfoModal} onOpenChange={setShowInfoModal} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -232,4 +232,53 @@ body {
|
||||
|
||||
.card-lg {
|
||||
@apply shadow-card-lg;
|
||||
}
|
||||
|
||||
/* Electron window drag regions */
|
||||
.draggable {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.non-draggable {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
/* 窗口控制按钮 */
|
||||
.window-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 0 10px;
|
||||
height: 30px;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.window-controls button {
|
||||
width: 45px;
|
||||
height: 30px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #000;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.window-controls button:hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.window-controls .close:hover {
|
||||
background: #ff5f56;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.window-controls .minimize:hover {
|
||||
background: #ffbd2e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.window-controls .maximize:hover {
|
||||
background: #27c93f;
|
||||
color: white;
|
||||
}
|
||||
Reference in New Issue
Block a user