"use client"; import { Maximize2, Minimize2, Minus, X } from "@/components/icons/platform-icons"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { useCallback, useEffect, useRef, useState } from "react"; type WindowProps = { title: string; icon?: React.ReactNode; children: React.ReactNode; onClose: () => void; onMinimize?: () => void; defaultWidth?: number; defaultHeight?: number; zIndex?: number; dockPosition?: "bottom" | "left" | "right"; onFocus?: () => void; isClosing?: boolean; isMinimized?: boolean; animationsEnabled?: boolean; }; const BOTTOM_DOCK_CLEARANCE = 88; const SIDE_DOCK_CLEARANCE = 80; export function Window({ title, icon, children, onClose, onMinimize, defaultWidth = 900, defaultHeight = 580, zIndex = 100, dockPosition = "bottom", onFocus, isClosing = false, isMinimized = false, animationsEnabled = true, }: WindowProps) { const [isMaximized, setIsMaximized] = useState(false); const [isVisible, setIsVisible] = useState(false); const [position, setPosition] = useState({ x: -1, y: -1 }); const [size, setSize] = useState({ w: defaultWidth, h: defaultHeight }); const [isDragging, setIsDragging] = useState(false); const [isResizing, setIsResizing] = useState(false); const dragOffset = useRef({ x: 0, y: 0 }); const windowRef = useRef(null); const preMaxState = useRef({ x: 0, y: 0, w: 0, h: 0 }); // Center on mount useEffect(() => { if (position.x === -1) { setPosition({ x: Math.max(40, (window.innerWidth - size.w) / 2), y: Math.max(50, (window.innerHeight - size.h) / 2 - 20), }); } }, [position.x, size.w, size.h]); useEffect(() => { if (!animationsEnabled) { setIsVisible(true); return; } const frame = window.requestAnimationFrame(() => setIsVisible(true)); return () => window.cancelAnimationFrame(frame); }, [animationsEnabled]); const handleMouseDown = useCallback( (e: React.MouseEvent) => { if (isMaximized) return; onFocus?.(); setIsDragging(true); dragOffset.current = { x: e.clientX - position.x, y: e.clientY - position.y, }; }, [isMaximized, position, onFocus], ); const handleResizeMouseDown = useCallback( (e: React.MouseEvent) => { if (isMaximized) return; e.stopPropagation(); onFocus?.(); setIsResizing(true); dragOffset.current = { x: e.clientX, y: e.clientY, }; }, [isMaximized, onFocus], ); useEffect(() => { if (!isDragging && !isResizing) return; const handleMouseMove = (e: MouseEvent) => { if (isDragging) { setPosition({ x: e.clientX - dragOffset.current.x, y: Math.max(0, e.clientY - dragOffset.current.y), }); } if (isResizing) { const dx = e.clientX - dragOffset.current.x; const dy = e.clientY - dragOffset.current.y; setSize((prev) => ({ w: Math.max(500, prev.w + dx), h: Math.max(350, prev.h + dy), })); dragOffset.current = { x: e.clientX, y: e.clientY }; } }; const handleMouseUp = () => { setIsDragging(false); setIsResizing(false); }; window.addEventListener("mousemove", handleMouseMove); window.addEventListener("mouseup", handleMouseUp); return () => { window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseup", handleMouseUp); }; }, [isDragging, isResizing]); function toggleMaximize() { if (isMaximized) { setPosition({ x: preMaxState.current.x, y: preMaxState.current.y }); setSize({ w: preMaxState.current.w, h: preMaxState.current.h }); setIsMaximized(false); } else { preMaxState.current = { x: position.x, y: position.y, w: size.w, h: size.h, }; setIsMaximized(true); } } const maximizedStyle = dockPosition === "left" ? { top: 0, right: 0, bottom: 0, left: SIDE_DOCK_CLEARANCE, zIndex, width: "auto", height: "auto", } : dockPosition === "right" ? { top: 0, right: SIDE_DOCK_CLEARANCE, bottom: 0, left: 0, zIndex, width: "auto", height: "auto", } : { top: 0, right: 0, bottom: BOTTOM_DOCK_CLEARANCE, left: 0, zIndex, width: "auto", height: "auto", }; if (isMinimized) return null; return (
onFocus?.()} > {/* Title bar */}
{/* Traffic lights */}
Close Minimize {isMaximized ? "Restore" : "Maximize"}
{icon} {title}
{/* Window content */}
{children}
{/* Resize handle */} {!isMaximized && (
)}
); }