You've already forked Nano-Banana-AI-Image-Editor
112 lines
3.1 KiB
TypeScript
112 lines
3.1 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { cn } from './utils/cn';
|
|
import { Header } from './components/Header';
|
|
import { PromptComposer } from './components/PromptComposer';
|
|
import { ImageCanvas } from './components/ImageCanvas';
|
|
import { HistoryPanel } from './components/HistoryPanel';
|
|
import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts';
|
|
import { useAppStore } from './store/useAppStore';
|
|
import { ToastProvider } from './components/ToastContext';
|
|
import * as indexedDBService from './services/indexedDBService';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 5 * 60 * 1000, // 5分钟
|
|
retry: 2,
|
|
},
|
|
},
|
|
});
|
|
|
|
function AppContent() {
|
|
useKeyboardShortcuts();
|
|
|
|
const { showPromptPanel, setShowPromptPanel, setShowHistory } = useAppStore();
|
|
|
|
// 在挂载时初始化IndexedDB并清理base64数据
|
|
useEffect(() => {
|
|
const init = async () => {
|
|
try {
|
|
await indexedDBService.initDB();
|
|
// 清理已有的base64数据
|
|
await indexedDBService.cleanupBase64Data();
|
|
} catch (err) {
|
|
console.error('初始化IndexedDB或清理base64数据失败:', err);
|
|
}
|
|
};
|
|
|
|
init();
|
|
}, []);
|
|
|
|
// 在挂载时设置移动设备默认值
|
|
React.useEffect(() => {
|
|
const checkMobile = () => {
|
|
const isMobile = window.innerWidth < 768;
|
|
if (isMobile) {
|
|
setShowPromptPanel(false);
|
|
setShowHistory(false);
|
|
}
|
|
};
|
|
|
|
checkMobile();
|
|
window.addEventListener('resize', checkMobile);
|
|
return () => window.removeEventListener('resize', checkMobile);
|
|
}, [setShowPromptPanel, setShowHistory]);
|
|
|
|
// 定期清理旧的历史记录
|
|
useEffect(() => {
|
|
const interval = setInterval(() => {
|
|
useAppStore.getState().cleanupOldHistory();
|
|
}, 30000); // 每30秒清理一次
|
|
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
// 定期清理未使用的Blob URL
|
|
useEffect(() => {
|
|
const interval = setInterval(() => {
|
|
useAppStore.getState().scheduleBlobCleanup();
|
|
}, 60000); // 每分钟清理一次
|
|
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
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>
|
|
|
|
<div className="flex-1 flex overflow-hidden p-4 gap-4">
|
|
<div className={cn("flex-shrink-0 transition-all duration-300 ease-in-out", !showPromptPanel && "w-8")}>
|
|
<div className="h-full card card-lg">
|
|
<PromptComposer />
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="h-full card card-lg">
|
|
<ImageCanvas />
|
|
</div>
|
|
</div>
|
|
<div className="flex-shrink-0">
|
|
<div className="h-full card card-lg">
|
|
<HistoryPanel />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<ToastProvider>
|
|
<AppContent />
|
|
</ToastProvider>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
export default App; |