Spaces:
Running
Running
| 'use client' | |
| import React, { useState, useEffect } from 'react' | |
| import { Dock } from './Dock' | |
| import { TopBar } from './TopBar' | |
| import { FileManager } from './FileManager' | |
| import { Calendar } from './Calendar' | |
| import { DraggableDesktopIcon } from './DraggableDesktopIcon' | |
| import { Messages } from './Messages' | |
| import { HelpModal } from './HelpModal' | |
| import { DesktopContextMenu } from './DesktopContextMenu' | |
| import { BackgroundSelector } from './BackgroundSelector' | |
| import { GeminiChat } from './GeminiChat' | |
| import { Clock } from './Clock' | |
| import { SpotlightSearch } from './SpotlightSearch' | |
| import { ContextMenu } from './ContextMenu' | |
| import { AboutModal } from './AboutModal' | |
| import { FlutterRunner } from './FlutterRunner' | |
| import { QuizApp } from './QuizApp' | |
| import { TextEditor } from './TextEditor' | |
| import { VoiceApp } from './VoiceApp' | |
| import { motion, AnimatePresence } from 'framer-motion' | |
| import { SystemPowerOverlay } from './SystemPowerOverlay' | |
| import { | |
| Folder, | |
| Calendar as CalendarIcon, | |
| Clock as ClockIcon, | |
| Globe, | |
| Sparkle, | |
| Terminal as TerminalIcon, | |
| Key, | |
| Brain, | |
| Code, | |
| FileText, | |
| DeviceMobile, | |
| Lightning, | |
| Function, | |
| ChatCircleDots, | |
| MusicNote | |
| } from '@phosphor-icons/react' | |
| export function Desktop() { | |
| const [fileManagerOpen, setFileManagerOpen] = useState(false) | |
| const [calendarOpen, setCalendarOpen] = useState(false) | |
| const [clockOpen, setClockOpen] = useState(false) | |
| const [messagesOpen, setMessagesOpen] = useState(false) | |
| const [geminiChatOpen, setGeminiChatOpen] = useState(false) | |
| const [spotlightOpen, setSpotlightOpen] = useState(false) | |
| const [contextMenuVisible, setContextMenuVisible] = useState(false) | |
| const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 }) | |
| const [currentPath, setCurrentPath] = useState('') | |
| const [helpModalOpen, setHelpModalOpen] = useState(false) | |
| const [contextMenuOpen, setContextMenuOpen] = useState(false) | |
| const [contextMenuPos, setContextMenuPos] = useState({ x: 0, y: 0 }) | |
| const [backgroundSelectorOpen, setBackgroundSelectorOpen] = useState(false) | |
| const [currentBackground, setCurrentBackground] = useState('https://images.unsplash.com/photo-1545159639-3f3534aa074e') | |
| const [aboutModalOpen, setAboutModalOpen] = useState(false) | |
| const [flutterRunnerOpen, setFlutterRunnerOpen] = useState(false) | |
| const [activeFlutterApp, setActiveFlutterApp] = useState<any>(null) | |
| const [flutterCodeEditorOpen, setFlutterCodeEditorOpen] = useState(false) | |
| const [quizAppOpen, setQuizAppOpen] = useState(false) | |
| const [textEditorOpen, setTextEditorOpen] = useState(false) | |
| const [activeTextFile, setActiveTextFile] = useState<{ content: string, fileName: string, filePath: string, passkey: string } | null>(null) | |
| const [voiceAppOpen, setVoiceAppOpen] = useState(false) | |
| // Minimized states | |
| const [fileManagerMinimized, setFileManagerMinimized] = useState(false) | |
| const [calendarMinimized, setCalendarMinimized] = useState(false) | |
| const [clockMinimized, setClockMinimized] = useState(false) | |
| const [messagesMinimized, setMessagesMinimized] = useState(false) | |
| const [geminiChatMinimized, setGeminiChatMinimized] = useState(false) | |
| const [flutterRunnerMinimized, setFlutterRunnerMinimized] = useState(false) | |
| const [flutterCodeEditorMinimized, setFlutterCodeEditorMinimized] = useState(false) | |
| const [quizAppMinimized, setQuizAppMinimized] = useState(false) | |
| const [textEditorMinimized, setTextEditorMinimized] = useState(false) | |
| const [voiceAppMinimized, setVoiceAppMinimized] = useState(false) | |
| const [powerState, setPowerState] = useState<'active' | 'sleep' | 'restart' | 'shutdown'>('active') | |
| const [globalZIndex, setGlobalZIndex] = useState(1000) | |
| const [windowZIndices, setWindowZIndices] = useState<{ [key: string]: number }>({}) | |
| const getNextZIndex = () => { | |
| const nextZ = globalZIndex + 1 | |
| setGlobalZIndex(nextZ) | |
| return nextZ | |
| } | |
| const bringWindowToFront = (windowId: string) => { | |
| setWindowZIndices(prev => ({ ...prev, [windowId]: getNextZIndex() })) | |
| } | |
| const closeAllApps = () => { | |
| // Close all apps | |
| setFileManagerOpen(false) | |
| setCalendarOpen(false) | |
| setClockOpen(false) | |
| setMessagesOpen(false) | |
| setGeminiChatOpen(false) | |
| setFlutterRunnerOpen(false) | |
| setFlutterCodeEditorOpen(false) | |
| setQuizAppOpen(false) | |
| setTextEditorOpen(false) | |
| setVoiceAppOpen(false) | |
| // Reset all minimized states | |
| setFileManagerMinimized(false) | |
| setCalendarMinimized(false) | |
| setClockMinimized(false) | |
| setMessagesMinimized(false) | |
| setGeminiChatMinimized(false) | |
| setFlutterRunnerMinimized(false) | |
| setFlutterCodeEditorMinimized(false) | |
| setQuizAppMinimized(false) | |
| setTextEditorMinimized(false) | |
| setVoiceAppMinimized(false) | |
| // Reset window z-indices | |
| setWindowZIndices({}) | |
| setGlobalZIndex(1000) | |
| } | |
| const openFileManager = (path: string) => { | |
| console.log('Opening File Manager with path:', path) | |
| setCurrentPath(path) | |
| setFileManagerOpen(true) | |
| setFileManagerMinimized(false) | |
| bringWindowToFront('fileManager') | |
| } | |
| const closeFileManager = () => { | |
| setFileManagerOpen(false) | |
| setFileManagerMinimized(false) | |
| } | |
| const openCalendar = () => { | |
| console.log('Opening Calendar') | |
| setCalendarOpen(true) | |
| setCalendarMinimized(false) | |
| bringWindowToFront('calendar') | |
| } | |
| const closeCalendar = () => { | |
| setCalendarOpen(false) | |
| setCalendarMinimized(false) | |
| } | |
| const openClock = () => { | |
| setClockOpen(true) | |
| setClockMinimized(false) | |
| bringWindowToFront('clock') | |
| } | |
| const closeClock = () => { | |
| setClockOpen(false) | |
| setClockMinimized(false) | |
| } | |
| const openMessages = () => { | |
| setMessagesOpen(true) | |
| setMessagesMinimized(false) | |
| bringWindowToFront('messages') | |
| } | |
| const closeMessages = () => { | |
| setMessagesOpen(false) | |
| setMessagesMinimized(false) | |
| } | |
| const openGeminiChat = () => { | |
| console.log('Opening Gemini Chat') | |
| setGeminiChatOpen(true) | |
| setGeminiChatMinimized(false) | |
| bringWindowToFront('gemini') | |
| } | |
| const closeGeminiChat = () => { | |
| setGeminiChatOpen(false) | |
| setGeminiChatMinimized(false) | |
| } | |
| const openFlutterRunner = (appFile: any) => { | |
| setActiveFlutterApp(appFile) | |
| setFlutterRunnerOpen(true) | |
| setFlutterRunnerMinimized(false) | |
| bringWindowToFront('flutterRunner') | |
| } | |
| const closeFlutterRunner = () => { | |
| setFlutterRunnerOpen(false) | |
| setFlutterRunnerMinimized(false) | |
| setActiveFlutterApp(null) | |
| } | |
| const openFlutterCodeEditor = () => { | |
| // Don't read/remove sessionStorage here - let FlutterRunner handle it | |
| // This allows the polling mechanism in FlutterRunner to detect new files | |
| setFlutterCodeEditorOpen(true) | |
| setFlutterCodeEditorMinimized(false) | |
| bringWindowToFront('flutterCodeEditor') | |
| } | |
| const closeFlutterCodeEditor = () => { | |
| setFlutterCodeEditorOpen(false) | |
| setFlutterCodeEditorMinimized(false) | |
| } | |
| const openQuizApp = () => { | |
| setQuizAppOpen(true) | |
| setQuizAppMinimized(false) | |
| bringWindowToFront('quizApp') | |
| } | |
| const closeQuizApp = () => { | |
| setQuizAppOpen(false) | |
| setQuizAppMinimized(false) | |
| } | |
| const openTextEditor = (fileData: { content: string, fileName: string, filePath: string, passkey: string }) => { | |
| setActiveTextFile(fileData) | |
| setTextEditorOpen(true) | |
| setTextEditorMinimized(false) | |
| bringWindowToFront('textEditor') | |
| } | |
| const closeTextEditor = () => { | |
| setTextEditorOpen(false) | |
| setTextEditorMinimized(false) | |
| setActiveTextFile(null) | |
| } | |
| const openVoiceApp = () => { | |
| setVoiceAppOpen(true) | |
| setVoiceAppMinimized(false) | |
| bringWindowToFront('voiceApp') | |
| } | |
| const closeVoiceApp = () => { | |
| setVoiceAppOpen(false) | |
| setVoiceAppMinimized(false) | |
| } | |
| const handleOpenApp = (appId: string) => { | |
| switch (appId) { | |
| case 'files': | |
| openFileManager('') | |
| break | |
| case 'calendar': | |
| openCalendar() | |
| break | |
| case 'clock': | |
| openClock() | |
| break | |
| case 'messages': | |
| openMessages() | |
| break | |
| case 'gemini': | |
| openGeminiChat() | |
| break | |
| case 'flutter-editor': | |
| openFlutterCodeEditor() | |
| break | |
| case 'quiz': | |
| openQuizApp() | |
| break | |
| case 'voice-app': | |
| openVoiceApp() | |
| break | |
| } | |
| } | |
| const handleContextMenuAction = (action: string) => { | |
| switch (action) { | |
| case 'change-wallpaper': | |
| setBackgroundSelectorOpen(true) | |
| break | |
| case 'get-info': | |
| setAboutModalOpen(true) | |
| break | |
| case 'refresh': | |
| window.location.reload() | |
| break | |
| } | |
| } | |
| const openHelpModal = () => { | |
| setHelpModalOpen(true) | |
| } | |
| const closeHelpModal = () => { | |
| setHelpModalOpen(false) | |
| } | |
| const handleDesktopRightClick = (e: React.MouseEvent) => { | |
| e.preventDefault() | |
| setContextMenuPosition({ x: e.clientX, y: e.clientY }) | |
| setContextMenuVisible(true) | |
| } | |
| const handleChangeBackground = (type: 'upload' | 'preset') => { | |
| setContextMenuOpen(false) | |
| setBackgroundSelectorOpen(true) | |
| } | |
| const handleSelectBackground = (background: string | File) => { | |
| if (typeof background === 'string') { | |
| // Handle preset backgrounds | |
| if (background.startsWith('gradient-')) { | |
| setCurrentBackground(background) | |
| } else { | |
| setCurrentBackground(background) | |
| } | |
| } else { | |
| // Handle uploaded file | |
| const url = URL.createObjectURL(background) | |
| setCurrentBackground(url) | |
| } | |
| } | |
| const handleSleep = () => setPowerState('sleep') | |
| const handleRestart = () => setPowerState('restart') | |
| const handleShutdown = () => setPowerState('shutdown') | |
| const handleWake = () => setPowerState('active') | |
| // Keyboard shortcuts | |
| useEffect(() => { | |
| const handleKeyDown = (e: KeyboardEvent) => { | |
| // Cmd/Ctrl + Space for Spotlight Search | |
| if ((e.metaKey || e.ctrlKey) && e.key === ' ') { | |
| e.preventDefault() | |
| setSpotlightOpen(true) | |
| } | |
| // Cmd/Ctrl + K for Spotlight Search (alternative) | |
| if ((e.metaKey || e.ctrlKey) && e.key === 'k') { | |
| e.preventDefault() | |
| setSpotlightOpen(true) | |
| } | |
| } | |
| window.addEventListener('keydown', handleKeyDown) | |
| return () => window.removeEventListener('keydown', handleKeyDown) | |
| }, []) | |
| const getBackgroundStyle = () => { | |
| if (currentBackground.startsWith('gradient-')) { | |
| const gradients: Record<string, string> = { | |
| 'gradient-sonoma': 'linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%)', | |
| 'gradient-purple': 'linear-gradient(135deg, #77216F 0%, #5E2750 50%, #2C001E 100%)', | |
| 'gradient-blue': 'linear-gradient(135deg, #1e3c72 0%, #2a5298 50%, #7e8ba3 100%)', | |
| 'gradient-green': 'linear-gradient(135deg, #134e5e 0%, #71b280 50%, #a8e063 100%)', | |
| 'gradient-orange': 'linear-gradient(135deg, #ff512f 0%, #dd2476 50%, #f09819 100%)', | |
| 'gradient-dark': 'linear-gradient(135deg, #0f0f0f 0%, #1a1a1a 50%, #2d2d2d 100%)', | |
| 'gradient-cosmic': 'linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%)' | |
| } | |
| return { background: gradients[currentBackground] || gradients['gradient-sonoma'] } | |
| } else { | |
| return { | |
| backgroundImage: `url('${currentBackground}')`, | |
| backgroundSize: 'cover', | |
| backgroundPosition: 'center', | |
| backgroundRepeat: 'no-repeat' | |
| } | |
| } | |
| } | |
| // Build minimized apps list for dock | |
| const minimizedApps = [] | |
| if (fileManagerMinimized && fileManagerOpen) { | |
| minimizedApps.push({ | |
| id: 'files', | |
| label: 'Files', | |
| icon: ( | |
| <div className="bg-gradient-to-br from-blue-400 to-cyan-200 w-full h-full rounded-xl flex items-center justify-center border border-white/30"> | |
| <Folder size={20} weight="regular" className="text-blue-900" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setFileManagerMinimized(false) | |
| bringWindowToFront('fileManager') | |
| } | |
| }) | |
| } | |
| if (calendarMinimized && calendarOpen) { | |
| minimizedApps.push({ | |
| id: 'calendar', | |
| label: 'Calendar', | |
| icon: ( | |
| <div className="bg-gradient-to-br from-purple-500 to-purple-600 w-full h-full rounded-xl flex items-center justify-center shadow-inner"> | |
| <CalendarIcon size={20} weight="regular" className="text-white" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setCalendarMinimized(false) | |
| bringWindowToFront('calendar') | |
| } | |
| }) | |
| } | |
| if (clockMinimized && clockOpen) { | |
| minimizedApps.push({ | |
| id: 'clock', | |
| label: 'Clock', | |
| icon: ( | |
| <div className="bg-black w-full h-full rounded-full flex items-center justify-center border border-gray-600"> | |
| <ClockIcon size={20} weight="regular" className="text-white" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setClockMinimized(false) | |
| bringWindowToFront('clock') | |
| } | |
| }) | |
| } | |
| if (messagesMinimized && messagesOpen) { | |
| minimizedApps.push({ | |
| id: 'messages', | |
| label: 'Messages', | |
| icon: ( | |
| <div className="bg-gradient-to-b from-[#4CD964] to-[#2E8B57] w-full h-full rounded-[22%] flex items-center justify-center shadow-lg border-[0.5px] border-white/20 relative overflow-hidden"> | |
| <div className="absolute inset-0 bg-gradient-to-b from-white/20 to-transparent opacity-50" /> | |
| <ChatCircleDots size={20} weight="fill" className="text-white relative z-10 drop-shadow-md" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setMessagesMinimized(false) | |
| bringWindowToFront('messages') | |
| } | |
| }) | |
| } | |
| if (geminiChatMinimized && geminiChatOpen) { | |
| minimizedApps.push({ | |
| id: 'gemini', | |
| label: 'Gemini', | |
| icon: ( | |
| <div className="bg-white w-full h-full rounded-xl flex items-center justify-center border border-gray-200"> | |
| <Sparkle size={20} weight="fill" className="text-blue-500" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setGeminiChatMinimized(false) | |
| bringWindowToFront('gemini') | |
| } | |
| }) | |
| } | |
| if (flutterRunnerMinimized && flutterRunnerOpen) { | |
| minimizedApps.push({ | |
| id: 'flutter-runner', | |
| label: 'Flutter Runner', | |
| icon: ( | |
| <div className="bg-gradient-to-b from-[#54C5F8] to-[#29B6F6] w-full h-full rounded-[22%] flex items-center justify-center shadow-lg border-[0.5px] border-white/20 relative overflow-hidden"> | |
| <div className="absolute inset-0 bg-gradient-to-b from-white/20 to-transparent opacity-50" /> | |
| <DeviceMobile size={20} weight="fill" className="text-white relative z-10 drop-shadow-md" /> | |
| <div className="absolute top-1 right-1"> | |
| <Lightning size={8} weight="fill" className="text-yellow-300 drop-shadow-md" /> | |
| </div> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setFlutterRunnerMinimized(false) | |
| bringWindowToFront('flutterRunner') | |
| } | |
| }) | |
| } | |
| if (flutterCodeEditorMinimized && flutterCodeEditorOpen) { | |
| minimizedApps.push({ | |
| id: 'flutter-editor', | |
| label: 'Flutter IDE', | |
| icon: ( | |
| <div className="bg-gradient-to-b from-[#54C5F8] to-[#29B6F6] w-full h-full rounded-[22%] flex items-center justify-center shadow-lg border-[0.5px] border-white/20 relative overflow-hidden"> | |
| <div className="absolute inset-0 bg-gradient-to-b from-white/20 to-transparent opacity-50" /> | |
| <DeviceMobile size={20} weight="fill" className="text-white relative z-10 drop-shadow-md" /> | |
| <div className="absolute top-1 right-1"> | |
| <Lightning size={8} weight="fill" className="text-yellow-300 drop-shadow-md" /> | |
| </div> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setFlutterCodeEditorMinimized(false) | |
| bringWindowToFront('flutterCodeEditor') | |
| } | |
| }) | |
| } | |
| if (quizAppMinimized && quizAppOpen) { | |
| minimizedApps.push({ | |
| id: 'quiz', | |
| label: 'Quiz Master', | |
| icon: ( | |
| <div className="bg-gradient-to-br from-teal-400 to-emerald-500 w-full h-full rounded-[22%] flex items-center justify-center shadow-lg border-[0.5px] border-white/20 relative overflow-hidden"> | |
| <div className="absolute inset-0 bg-gradient-to-b from-white/20 to-transparent opacity-50" /> | |
| <Brain size={20} weight="fill" className="text-white relative z-10 drop-shadow-md" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setQuizAppMinimized(false) | |
| bringWindowToFront('quizApp') | |
| } | |
| }) | |
| } | |
| if (textEditorMinimized && textEditorOpen) { | |
| minimizedApps.push({ | |
| id: 'text-editor', | |
| label: activeTextFile?.fileName || 'Text Editor', | |
| icon: ( | |
| <div className="bg-gradient-to-br from-gray-700 to-gray-900 w-full h-full rounded-[22%] flex items-center justify-center shadow-lg border-[0.5px] border-white/20 relative overflow-hidden"> | |
| <div className="absolute inset-0 bg-gradient-to-b from-white/10 to-transparent opacity-30" /> | |
| <FileText size={20} weight="fill" className="text-blue-400 relative z-10 drop-shadow-md" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setTextEditorMinimized(false) | |
| bringWindowToFront('textEditor') | |
| } | |
| }) | |
| } | |
| if (voiceAppMinimized && voiceAppOpen) { | |
| minimizedApps.push({ | |
| id: 'voice-app', | |
| label: 'Voice Studio', | |
| icon: ( | |
| <div className="bg-gradient-to-br from-purple-500 to-pink-500 w-full h-full rounded-[22%] flex items-center justify-center shadow-lg border-[0.5px] border-white/20 relative overflow-hidden"> | |
| <div className="absolute inset-0 bg-gradient-to-b from-white/20 to-transparent opacity-50" /> | |
| <MusicNote size={20} weight="fill" className="text-white relative z-10 drop-shadow-md" /> | |
| </div> | |
| ), | |
| onRestore: () => { | |
| setVoiceAppMinimized(false) | |
| bringWindowToFront('voiceApp') | |
| } | |
| }) | |
| } | |
| // Debug info | |
| useEffect(() => { | |
| console.log('App States:', { | |
| fileManagerOpen, | |
| calendarOpen, | |
| clockOpen, | |
| messagesOpen, | |
| geminiChatOpen, | |
| fileManagerMinimized, | |
| calendarMinimized, | |
| clockMinimized, | |
| messagesMinimized, | |
| geminiChatMinimized | |
| }) | |
| }, [fileManagerOpen, calendarOpen, clockOpen, messagesOpen, geminiChatOpen, fileManagerMinimized, calendarMinimized, clockMinimized, messagesMinimized, geminiChatMinimized]) | |
| return ( | |
| <div className="relative h-screen w-screen overflow-hidden flex touch-auto" onContextMenu={handleDesktopRightClick}> | |
| <div | |
| className="absolute inset-0 transition-all duration-500 ease-in-out" | |
| style={getBackgroundStyle()} | |
| > | |
| {/* Overlay for better text visibility */} | |
| {!currentBackground.startsWith('gradient-') && ( | |
| <div | |
| className="absolute inset-0 bg-black/20" | |
| style={{ | |
| mixBlendMode: 'multiply' | |
| }} | |
| /> | |
| )} | |
| <svg className="absolute inset-0 w-full h-full opacity-10 pointer-events-none" xmlns="http://www.w3.org/2000/svg"> | |
| <defs> | |
| <pattern id="ubuntu-pattern" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse"> | |
| <circle cx="50" cy="50" r="2" fill="white" opacity="0.3" /> | |
| </pattern> | |
| </defs> | |
| <rect width="100%" height="100%" fill="url(#ubuntu-pattern)" /> | |
| </svg> | |
| </div> | |
| <TopBar | |
| onAboutClick={() => setAboutModalOpen(true)} | |
| onSleep={handleSleep} | |
| onRestart={handleRestart} | |
| onShutdown={handleShutdown} | |
| /> | |
| <Dock | |
| onOpenFileManager={openFileManager} | |
| onOpenCalendar={openCalendar} | |
| onOpenClock={openClock} | |
| onOpenMessages={openMessages} | |
| onOpenGeminiChat={openGeminiChat} | |
| onCloseAllApps={closeAllApps} | |
| openApps={{ | |
| files: fileManagerOpen, | |
| calendar: calendarOpen, | |
| clock: clockOpen, | |
| messages: messagesOpen, | |
| gemini: geminiChatOpen | |
| }} | |
| minimizedApps={minimizedApps} | |
| /> | |
| <div className="flex-1 z-10 relative pointer-events-auto"> | |
| {/* Desktop Icons - Responsive grid layout, visible on all screen sizes */} | |
| <div className="absolute top-16 left-2 right-2 sm:left-4 sm:right-4 bottom-24 grid grid-cols-3 xs:grid-cols-4 sm:grid-cols-4 md:grid-cols-5 lg:grid-flow-col lg:grid-cols-none lg:grid-rows-[repeat(auto-fill,100px)] gap-2 sm:gap-4 pointer-events-none overflow-y-auto lg:overflow-visible z-0"> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="files" | |
| label="Files" | |
| iconType="files" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={() => openFileManager('')} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="messages" | |
| label="Messages" | |
| iconType="messages" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openMessages} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="gemini" | |
| label="Gemini" | |
| iconType="gemini" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openGeminiChat} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="clock" | |
| label="Clock" | |
| iconType="clock" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openClock} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="calendar" | |
| label="Calendar" | |
| iconType="calendar" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openCalendar} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="harddrive" | |
| label="System" | |
| iconType="harddrive" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={() => openFileManager('')} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="flutter-editor" | |
| label="Flutter IDE" | |
| iconType="flutter" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openFlutterCodeEditor} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="quiz" | |
| label="Quiz Master" | |
| iconType="quiz" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openQuizApp} | |
| /> | |
| </div> | |
| <div className="pointer-events-auto w-20 h-20 sm:w-24 sm:h-24"> | |
| <DraggableDesktopIcon | |
| id="voice-app" | |
| label="Voice Studio" | |
| iconType="voice-app" | |
| initialPosition={{ x: 0, y: 0 }} | |
| onClick={() => { }} | |
| onDoubleClick={openVoiceApp} | |
| /> | |
| </div> | |
| </div> | |
| {/* Windows Container - adjusted for mobile topbar height */} | |
| <div className="fixed inset-0 pointer-events-none" style={{ position: 'fixed', top: '40px', left: 0, right: 0, bottom: 0 }}> | |
| <AnimatePresence> | |
| {fileManagerOpen && ( | |
| <motion.div | |
| key="file-manager" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: fileManagerMinimized ? 0 : 1, | |
| scale: fileManagerMinimized ? 0.9 : 1, | |
| y: fileManagerMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: fileManagerMinimized ? 'none' : 'auto', | |
| display: fileManagerMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <FileManager | |
| currentPath={currentPath} | |
| onNavigate={setCurrentPath} | |
| onClose={closeFileManager} | |
| onOpenFlutterApp={openFlutterRunner} | |
| onMinimize={() => setFileManagerMinimized(true)} | |
| onFocus={() => bringWindowToFront('fileManager')} | |
| zIndex={windowZIndices.fileManager || 1000} | |
| onOpenApp={handleOpenApp} | |
| onOpenTextFile={openTextEditor} | |
| /> | |
| </motion.div> | |
| )} | |
| {calendarOpen && ( | |
| <motion.div | |
| key="calendar" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: calendarMinimized ? 0 : 1, | |
| scale: calendarMinimized ? 0.9 : 1, | |
| y: calendarMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: calendarMinimized ? 'none' : 'auto', | |
| display: calendarMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <Calendar | |
| onClose={closeCalendar} | |
| onMinimize={() => setCalendarMinimized(true)} | |
| onFocus={() => bringWindowToFront('calendar')} | |
| zIndex={windowZIndices.calendar || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {clockOpen && ( | |
| <motion.div | |
| key="clock" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: clockMinimized ? 0 : 1, | |
| scale: clockMinimized ? 0.9 : 1, | |
| y: clockMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: clockMinimized ? 'none' : 'auto', | |
| display: clockMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <Clock | |
| onClose={closeClock} | |
| onMinimize={() => setClockMinimized(true)} | |
| onFocus={() => bringWindowToFront('clock')} | |
| zIndex={windowZIndices.clock || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {messagesOpen && ( | |
| <motion.div | |
| key="messages" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: messagesMinimized ? 0 : 1, | |
| scale: messagesMinimized ? 0.9 : 1, | |
| y: messagesMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: messagesMinimized ? 'none' : 'auto', | |
| display: messagesMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <Messages | |
| onClose={closeMessages} | |
| onMinimize={() => setMessagesMinimized(true)} | |
| onFocus={() => bringWindowToFront('messages')} | |
| zIndex={windowZIndices.messages || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {geminiChatOpen && ( | |
| <motion.div | |
| key="gemini" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: geminiChatMinimized ? 0 : 1, | |
| scale: geminiChatMinimized ? 0.9 : 1, | |
| y: geminiChatMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: geminiChatMinimized ? 'none' : 'auto', | |
| display: geminiChatMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <GeminiChat | |
| onClose={closeGeminiChat} | |
| onMinimize={() => setGeminiChatMinimized(true)} | |
| onFocus={() => bringWindowToFront('gemini')} | |
| zIndex={windowZIndices.gemini || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {flutterRunnerOpen && activeFlutterApp && ( | |
| <motion.div | |
| key="flutter-runner" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: flutterRunnerMinimized ? 0 : 1, | |
| scale: flutterRunnerMinimized ? 0.9 : 1, | |
| y: flutterRunnerMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: flutterRunnerMinimized ? 'none' : 'auto', | |
| display: flutterRunnerMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <FlutterRunner | |
| onClose={() => { | |
| setFlutterRunnerOpen(false) | |
| setActiveFlutterApp(null) | |
| }} | |
| onMinimize={() => setFlutterRunnerMinimized(true)} | |
| onFocus={() => bringWindowToFront('flutterRunner')} | |
| zIndex={windowZIndices.flutterRunner || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {flutterCodeEditorOpen && ( | |
| <motion.div | |
| key="flutter-code-editor" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: flutterCodeEditorMinimized ? 0 : 1, | |
| scale: flutterCodeEditorMinimized ? 0.9 : 1, | |
| y: flutterCodeEditorMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: flutterCodeEditorMinimized ? 'none' : 'auto', | |
| display: flutterCodeEditorMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <FlutterRunner | |
| onClose={closeFlutterCodeEditor} | |
| onMinimize={() => setFlutterCodeEditorMinimized(true)} | |
| onFocus={() => bringWindowToFront('flutterCodeEditor')} | |
| zIndex={windowZIndices.flutterCodeEditor || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {quizAppOpen && ( | |
| <motion.div | |
| key="quiz-app" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: quizAppMinimized ? 0 : 1, | |
| scale: quizAppMinimized ? 0.9 : 1, | |
| y: quizAppMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: quizAppMinimized ? 'none' : 'auto', | |
| display: quizAppMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <QuizApp | |
| onClose={closeQuizApp} | |
| onMinimize={() => setQuizAppMinimized(true)} | |
| onFocus={() => bringWindowToFront('quizApp')} | |
| zIndex={windowZIndices.quizApp || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {textEditorOpen && activeTextFile && ( | |
| <motion.div | |
| key="text-editor" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: textEditorMinimized ? 0 : 1, | |
| scale: textEditorMinimized ? 0.9 : 1, | |
| y: textEditorMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: textEditorMinimized ? 'none' : 'auto', | |
| display: textEditorMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <TextEditor | |
| initialContent={activeTextFile.content} | |
| fileName={activeTextFile.fileName} | |
| filePath={activeTextFile.filePath} | |
| passkey={activeTextFile.passkey} | |
| onClose={closeTextEditor} | |
| onMinimize={() => setTextEditorMinimized(true)} | |
| onFocus={() => bringWindowToFront('textEditor')} | |
| zIndex={windowZIndices.textEditor || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| {voiceAppOpen && ( | |
| <motion.div | |
| key="voice-app" | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| animate={{ | |
| opacity: voiceAppMinimized ? 0 : 1, | |
| scale: voiceAppMinimized ? 0.9 : 1, | |
| y: voiceAppMinimized ? 100 : 0, | |
| }} | |
| exit={{ opacity: 0, scale: 0.95 }} | |
| transition={{ duration: 0.2 }} | |
| style={{ | |
| pointerEvents: voiceAppMinimized ? 'none' : 'auto', | |
| display: voiceAppMinimized ? 'none' : 'block' | |
| }} | |
| > | |
| <VoiceApp | |
| onClose={closeVoiceApp} | |
| onMinimize={() => setVoiceAppMinimized(true)} | |
| onFocus={() => bringWindowToFront('voiceApp')} | |
| zIndex={windowZIndices.voiceApp || 1000} | |
| /> | |
| </motion.div> | |
| )} | |
| </AnimatePresence> | |
| </div> | |
| </div> | |
| {/* Spotlight Search */} | |
| <SpotlightSearch | |
| isOpen={spotlightOpen} | |
| onClose={() => setSpotlightOpen(false)} | |
| onOpenApp={handleOpenApp} | |
| /> | |
| {/* Context Menu */} | |
| <ContextMenu | |
| isOpen={contextMenuVisible} | |
| position={contextMenuPosition} | |
| onClose={() => setContextMenuVisible(false)} | |
| onAction={handleContextMenuAction} | |
| /> | |
| {/* Help Modal */} | |
| <HelpModal isOpen={helpModalOpen} onClose={closeHelpModal} /> | |
| {/* Desktop Context Menu */} | |
| <DesktopContextMenu | |
| isOpen={contextMenuOpen} | |
| position={contextMenuPos} | |
| onClose={() => setContextMenuOpen(false)} | |
| onChangeBackground={handleChangeBackground} | |
| /> | |
| {/* Background Selector Modal */} | |
| <BackgroundSelector | |
| isOpen={backgroundSelectorOpen} | |
| onClose={() => setBackgroundSelectorOpen(false)} | |
| onSelectBackground={handleSelectBackground} | |
| currentBackground={currentBackground} | |
| /> | |
| {/* System Power Overlay */} | |
| <SystemPowerOverlay | |
| state={powerState} | |
| onWake={handleWake} | |
| onRestartComplete={handleWake} | |
| /> | |
| {/* About Modal */} | |
| <AboutModal | |
| isOpen={aboutModalOpen} | |
| onClose={() => setAboutModalOpen(false)} | |
| /> | |
| </div> | |
| ) | |
| } | |