From 4d5e4674e3131f67a8ab740e3d2e1e464612b93a Mon Sep 17 00:00:00 2001 From: sirpiglr <49359077-sirpiglr@users.noreply.replit.com> Date: Sun, 21 Dec 2025 03:30:18 +0000 Subject: [PATCH] Improve desktop management by associating windows with specific desktops Refactors the window management system to include a `desktopId` property for each window, allowing windows to be associated with specific virtual desktops. This change impacts the `WindowState` interface, `openApp`, `closeWindow`, and `onLoadLayout` functions, and updates the rendering of windows in the taskbar and main display to only show windows belonging to the `currentDesktop`. Additionally, new tray panel states for audio and battery have been introduced. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 279f1558-c0e3-40e4-8217-be7e9f4c6eca Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 9186b2b0-64d9-45e3-9acd-f325d9d49cff Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/b984cb14-1d19-4944-922b-bc79e821ed35/279f1558-c0e3-40e4-8217-be7e9f4c6eca/NVB9NVD Replit-Helium-Checkpoint-Created: true --- attached_assets/image_1766286925377.png | Bin 0 -> 3081 bytes client/public/opengraph.jpg | Bin 6159 -> 11714 bytes client/src/pages/os.tsx | 308 ++++++++++++++++++++++-- 3 files changed, 285 insertions(+), 23 deletions(-) create mode 100644 attached_assets/image_1766286925377.png diff --git a/attached_assets/image_1766286925377.png b/attached_assets/image_1766286925377.png new file mode 100644 index 0000000000000000000000000000000000000000..0d438c6b9baf30b585968ef7f2a3528592934263 GIT binary patch literal 3081 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 oalP46Pi&wwKw?x0IS|_zyJUM delta 131 zcmX>U-EXj=k10cxfsv5`6>$7N!XP4mF3JED6=lRw%m`8}h^hD%0}nGJ1Ct=LAcH-_ Y42FQsiOk0An+up#K*WAFX8Hd&0W(Dt4*&oF diff --git a/client/src/pages/os.tsx b/client/src/pages/os.tsx index 51fb99d..2667d2d 100644 --- a/client/src/pages/os.tsx +++ b/client/src/pages/os.tsx @@ -29,6 +29,7 @@ interface WindowState { maximized: boolean; zIndex: number; accentColor?: string; + desktopId: number; } interface Toast { @@ -193,6 +194,24 @@ export default function AeThexOS() { const spotlightRef = useRef(null); const { user, isAuthenticated, logout } = useAuth(); const [, setLocation] = useLocation(); + const [activeTrayPanel, setActiveTrayPanel] = useState<'wifi' | 'volume' | 'battery' | 'notifications' | null>(null); + const [volume, setVolume] = useState(75); + const [isMuted, setIsMuted] = useState(false); + const [batteryInfo, setBatteryInfo] = useState<{ level: number; charging: boolean } | null>(null); + + useEffect(() => { + if ('getBattery' in navigator) { + (navigator as any).getBattery().then((battery: any) => { + setBatteryInfo({ level: Math.round(battery.level * 100), charging: battery.charging }); + battery.addEventListener('levelchange', () => { + setBatteryInfo(prev => prev ? { ...prev, level: Math.round(battery.level * 100) } : null); + }); + battery.addEventListener('chargingchange', () => { + setBatteryInfo(prev => prev ? { ...prev, charging: battery.charging } : null); + }); + }); + } + }, []); const { data: weatherData, isFetching: weatherFetching } = useQuery({ queryKey: ['weather'], @@ -440,15 +459,9 @@ export default function AeThexOS() { playSound('open'); const existingWindow = windows.find(w => w.id === app.id); if (existingWindow) { - if (existingWindow.minimized) { - setWindows(prev => prev.map(w => - w.id === app.id ? { ...w, minimized: false, zIndex: maxZIndex + 1 } : w - )); - } else { - setWindows(prev => prev.map(w => - w.id === app.id ? { ...w, zIndex: maxZIndex + 1 } : w - )); - } + setWindows(prev => prev.map(w => + w.id === app.id ? { ...w, minimized: false, zIndex: maxZIndex + 1, desktopId: currentDesktop } : w + )); setMaxZIndex(prev => prev + 1); setActiveWindowId(app.id); return; @@ -468,14 +481,15 @@ export default function AeThexOS() { height: app.defaultHeight, minimized: false, maximized: false, - zIndex: maxZIndex + 1 + zIndex: maxZIndex + 1, + desktopId: currentDesktop }; setWindows(prev => [...prev, newWindow]); setMaxZIndex(prev => prev + 1); setActiveWindowId(app.id); setShowStartMenu(false); - }, [windows, maxZIndex, playSound]); + }, [windows, maxZIndex, playSound, currentDesktop]); const closeWindow = useCallback((id: string) => { playSound('close'); @@ -616,8 +630,9 @@ export default function AeThexOS() { layout.windows.forEach((w, i) => { const app = apps.find(a => a.component === w.appId); if (app) { + const windowId = `${app.id}-${Date.now()}-${i}`; setWindows(prev => [...prev, { - id: `${app.id}-${Date.now()}-${i}`, + id: windowId, title: app.title, icon: app.icon, component: app.component, @@ -628,6 +643,7 @@ export default function AeThexOS() { minimized: false, maximized: false, zIndex: i + 1, + desktopId: layout.desktop }]); } }); @@ -734,7 +750,7 @@ export default function AeThexOS() { - {windows.filter(w => !w.minimized).map((window) => ( + {windows.filter(w => !w.minimized && w.desktopId === currentDesktop).map((window) => ( w.desktopId === currentDesktop)} activeWindowId={activeWindowId} apps={apps} time={time} @@ -779,7 +795,7 @@ export default function AeThexOS() { isAuthenticated={isAuthenticated} notifications={notifications} showNotifications={showNotifications} - onToggleStartMenu={() => setShowStartMenu(!showStartMenu)} + onToggleStartMenu={() => { setShowStartMenu(!showStartMenu); setActiveTrayPanel(null); }} onToggleNotifications={() => setShowNotifications(!showNotifications)} onWindowClick={(id) => { const window = windows.find(w => w.id === id); @@ -793,9 +809,22 @@ export default function AeThexOS() { onLogout={handleLogout} onNavigate={setLocation} currentDesktop={currentDesktop} - onDesktopChange={setCurrentDesktop} + onDesktopChange={(d) => { + setCurrentDesktop(d); + setActiveTrayPanel(null); + }} clearanceTheme={clearanceTheme} onSwitchClearance={switchClearance} + activeTrayPanel={activeTrayPanel} + onTrayPanelToggle={(panel) => setActiveTrayPanel(activeTrayPanel === panel ? null : panel)} + volume={volume} + onVolumeChange={setVolume} + isMuted={isMuted} + onMuteToggle={() => setIsMuted(!isMuted)} + batteryInfo={batteryInfo} + onClearNotification={(idx) => setNotifications(prev => prev.filter((_, i) => i !== idx))} + onClearAllNotifications={() => setNotifications([])} + desktopWindowCounts={[0, 1, 2, 3].map(d => windows.filter(w => w.desktopId === d).length)} /> @@ -1250,6 +1279,16 @@ interface TaskbarProps { onDesktopChange: (d: number) => void; clearanceTheme: ClearanceTheme; onSwitchClearance: () => void; + activeTrayPanel: 'wifi' | 'volume' | 'battery' | 'notifications' | null; + onTrayPanelToggle: (panel: 'wifi' | 'volume' | 'battery' | 'notifications') => void; + volume: number; + onVolumeChange: (v: number) => void; + isMuted: boolean; + onMuteToggle: () => void; + batteryInfo: { level: number; charging: boolean } | null; + onClearNotification: (index: number) => void; + onClearAllNotifications: () => void; + desktopWindowCounts: number[]; } function Skeleton({ className = "", animate = true }: { className?: string; animate?: boolean }) { @@ -1457,7 +1496,7 @@ function OnboardingTour({ step, onNext, onClose }: { step: number; onNext: () => ); } -function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isAuthenticated, notifications, showNotifications, onToggleStartMenu, onToggleNotifications, onWindowClick, onAppClick, onLogout, onNavigate, currentDesktop, onDesktopChange, clearanceTheme, onSwitchClearance }: TaskbarProps) { +function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isAuthenticated, notifications, showNotifications, onToggleStartMenu, onToggleNotifications, onWindowClick, onAppClick, onLogout, onNavigate, currentDesktop, onDesktopChange, clearanceTheme, onSwitchClearance, activeTrayPanel, onTrayPanelToggle, volume, onVolumeChange, isMuted, onMuteToggle, batteryInfo, onClearNotification, onClearAllNotifications, desktopWindowCounts }: TaskbarProps) { return ( <> @@ -1681,19 +1720,26 @@ function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isA ))} -
- - - - + + +
{time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
+ + + {activeTrayPanel === 'notifications' && ( + e.stopPropagation()} + > +
+ Notifications + {notifications.length > 0 && ( + + )} +
+
+ {notifications.length === 0 ? ( +
No notifications
+ ) : ( + notifications.map((notif, idx) => ( +
+ +

{notif}

+ +
+ )) + )} +
+
+ )} + + {activeTrayPanel === 'wifi' && ( + e.stopPropagation()} + > +
+ Network Status +
+
+
+
+ +
+
+
AeThex Network
+
Connected
+
+
+
+
+ Signal Strength + Excellent +
+
+ Protocol + AEGIS-256 +
+
+ Latency + 2ms +
+
+ Node + AXIOM-CORE-01 +
+
+
+
+
+ Secure Connection Active +
+
+
+ + )} + + {activeTrayPanel === 'volume' && ( + e.stopPropagation()} + > +
+ Sound +
+
+
+ +
+
{isMuted ? 'Muted' : 'Volume'}
+
{isMuted ? 'Click to unmute' : `${volume}%`}
+
+
+
+ onVolumeChange(parseInt(e.target.value))} + className="w-full h-2 bg-white/10 rounded-lg appearance-none cursor-pointer accent-cyan-500" + style={{ accentColor: '#06b6d4' }} + /> +
+ 0 + 50 + 100 +
+
+
+
+ OS Sounds + {isMuted ? 'OFF' : 'ON'} +
+
+
+
+ )} + + {activeTrayPanel === 'battery' && ( + e.stopPropagation()} + > +
+ Power +
+
+
+
+ +
+
+
+ {batteryInfo ? `${batteryInfo.level}%` : 'Unknown'} +
+
+ {batteryInfo?.charging ? 'Charging' : 'On Battery'} +
+
+
+ {batteryInfo && ( +
+
+
50 ? 'bg-green-500' : + batteryInfo.level > 20 ? 'bg-yellow-500' : 'bg-red-500' + }`} + style={{ width: `${batteryInfo.level}%` }} + /> +
+
+ 0% + 50% + 100% +
+
+ )} + {!batteryInfo && ( +
+ Battery API not available +
+ )} +
+
+ Power Mode + Balanced +
+
+ Status + Optimal +
+
+
+ + )} +