diff --git a/src/app/page.tsx b/src/app/page.tsx index 3dbee5c..c8cf4c0 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -6,35 +6,38 @@ import HomeText from "@/components/home-text.mdx" import Link from "next/link"; import { FakeWindow, HomeWindows } from "@/components/windows"; import Taskbar from "@/components/taskbar"; +import { WindowManagerProvider } from "@/hooks/window-manager"; export default function Home() { return (<> - - - - - Nonszy Workspace - - - - - - - - - - - - ⚡ Powered with Cloudflare ☁️ - - - + + + + + + Nonszy Workspace + + + + + + + + + + + + ⚡ Powered with Cloudflare ☁️ + + + + >); } diff --git a/src/components/client-windows.tsx b/src/components/client-windows.tsx index 174ab8a..b51c226 100644 --- a/src/components/client-windows.tsx +++ b/src/components/client-windows.tsx @@ -1,8 +1,23 @@ 'use client' +import { FakeWindow, useWindowManager } from "@/hooks/window-manager"; import { Icon } from "@iconify/react"; import clsx from "clsx"; -import { useState, useRef, useEffect } from "react"; +import React, { useState, useRef, useEffect, useReducer } from "react"; + +export const RestoreWindowsButton = ({ onClick, className, ...props}: React.ComponentProps<"button">) => { + const windowManager = useWindowManager(); + + const isAnyWindowsClosed = !windowManager.windows.find(w => w.closed == true); + + return ( + + ) +} export const FakeRelativeWindow = ({ windowText, @@ -17,12 +32,15 @@ export const FakeRelativeWindow = ({ withAnim?: boolean, children: React.ReactNode }) => { - const [isMinimized, setMinimize] = useState(false); - const [offset, setOffset] = useState({ x: 0, y: 0 }); + const windowManager = useWindowManager(); + const windowName = windowText.toLocaleLowerCase(); + const currentWindow = windowManager.get(windowName); + const [animation, setAnimation] = useState({ window: "animate-window-popup", content: "animate-[fade-in-half_1s]" }); + const popupRef = useRef(null); const pos = useRef({ dragging: false, @@ -32,6 +50,32 @@ export const FakeRelativeWindow = ({ y: 0 }); + const populateWindow = () => { + windowManager.add({ + name: windowName, + closed: false, + minimized: false, + offset: { x: 0, y: 0 } + }) + } + + useEffect(() => { + if (!windowManager.isLocalDataExists) { + if (!currentWindow) populateWindow(); + return () => { + windowManager.remove(windowName); + } + } + }, []); + + useEffect(() => { + console.log(windowManager.windows) + }, [windowManager.windows]); + + useEffect(() => { + if (popupRef.current) popupRef.current.style.transform = `translate(${currentWindow?.offset.x || 0}px, ${currentWindow?.offset.y || 0}px)`; + }, [currentWindow?.offset]) + useEffect(() => { if (!withAnim) return; const node = popupRef.current; @@ -56,16 +100,17 @@ export const FakeRelativeWindow = ({ return () => observer.disconnect(); }, []); - const toggleMinimize = () => setMinimize(!isMinimized); + const toggleMinimize = () => windowManager.toggleMinimize(windowName); + const handleClose = () => windowManager.close(windowName); const onMouseDown = (e: React.MouseEvent) => { - if (!draggable) return; + if (!draggable || !currentWindow) return; if (popupRef.current) { pos.current.dragging = true; pos.current.mouseX = e.clientX; pos.current.mouseY = e.clientY; - pos.current.x = offset.x; - pos.current.y = offset.y; + pos.current.x = currentWindow.offset.x; + pos.current.y = currentWindow.offset.y; document.body.style.userSelect = "none"; } window.addEventListener("mousemove", onMouseMove); @@ -80,16 +125,21 @@ export const FakeRelativeWindow = ({ }; const onMouseMove = (e: MouseEvent) => { + if (!currentWindow) return; if (pos.current.dragging && popupRef.current) { const dx = e.clientX - pos.current.mouseX; const dy = e.clientY - pos.current.mouseY; const newX = pos.current.x + dx; const newY = pos.current.y + dy; - popupRef.current.style.transform = `translate(${newX}px, ${newY}px)`; - setOffset({ x: newX, y: newY }); + windowManager.move(windowName, { + x: newX, + y: newY + }); } }; + if (!currentWindow || currentWindow?.closed) return + return ( @@ -98,14 +148,24 @@ export const FakeRelativeWindow = ({ onMouseDown={onMouseDown} > - {windowText} + {currentWindow ? currentWindow.name : "Error!"} - - + + + + + + - + {children} diff --git a/src/components/floating-label.tsx b/src/components/floating-label.tsx index 9a3203d..85a1ee6 100644 --- a/src/components/floating-label.tsx +++ b/src/components/floating-label.tsx @@ -8,10 +8,8 @@ export const FloatingLabel = ({ children: React.ReactNode; }) => { return ( - - - {children} - - + + {children} + ); }; \ No newline at end of file diff --git a/src/components/windows.tsx b/src/components/windows.tsx index 8512dc0..7ca3149 100644 --- a/src/components/windows.tsx +++ b/src/components/windows.tsx @@ -1,6 +1,6 @@ import { Icon } from "@iconify/react"; import { FloatingLabel } from "@/components/floating-label"; -import { FakeRelativeWindow } from "./client-windows"; +import { FakeRelativeWindow, RestoreWindowsButton } from "./client-windows"; import Image from "next/image" import Link from "next/link"; @@ -16,12 +16,17 @@ export const FakeWindow = ({ {windowText} - - - - - - + + + Restore Windows + + + + + + + + @@ -34,23 +39,6 @@ export const FakeWindow = ({ export const HomeWindows = () => ( - {/* - - - Join my Left 4 Dead 2 server! - - */} FakeWindow | undefined; + add: (window: FakeWindow) => void; + updateWindow: (name: string, changes: Partial) => void; + toggleMinimize: (name: string) => void; + close: (name: string) => void; + remove: (name: string) => void; + move: (name: string, offset: { x: number; y: number }) => void; + openAll: () => void; +} + +const WindowManagerContext = createContext(undefined); + +export const WindowManagerProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [windows, setWindows] = useState([]); + const [isInit, setInit] = useState(false); + const [isLocalDataExists, setExists] = useState(false); + + useEffect(() => { + const data = localStorage.getItem("fake-windows-data"); + if (data) { + setWindows(JSON.parse(data)); + setExists(true); + } + setInit(true); + }, []); + + useEffect(() => { + if (isInit && typeof window !== 'undefined' && windows.length > 0) { + window.localStorage.setItem('fake-windows-data', JSON.stringify(windows)); + } + }, [windows]); + + const get = (name: string) => windows.find(window => window.name == name); + const add = (window: FakeWindow) => setWindows(w => [...w, window]); + const updateWindow = (name: string, changes: Partial) => + setWindows(w => + w.map(win => win.name === name ? { ...win, ...changes } : win) + ); + const toggleMinimize = (name: string) => + setWindows(w => + w.map(win => win.name === name ? { ...win, minimized: !win.minimized } : win) + ); + const open = (name: string) => updateWindow(name, { closed: false }); + const close = (name: string) => updateWindow(name, { closed: true }); + const move = (name: string, offset: { x: number; y: number }) => + updateWindow(name, { offset }); + + const remove = (name: string) => setWindows(w => w.filter(win => win.name !== name)); + + const openAll = () => setWindows(w => + w.map(win => ({ ...win, closed: false })) + ); + + return ( + + {children} + + ); +}; + +export function useWindowManager() { + const ctx = useContext(WindowManagerContext); + if (!ctx) throw new Error("useWindowManager must be used within WindowManagerProvider"); + return ctx; } \ No newline at end of file
⚡ Powered with Cloudflare ☁️
Join my Left 4 Dead 2 server!