1- import { useRef } from "react" ;
1+ import { useRef , useState } from "react" ;
22import { v4 as uuid } from "uuid" ;
33
44import useConditionalClick from "../../../hooks/useConditionalClick" ;
55import useWindowManagerStore from "../../../stores/windowManagerStore" ;
66import BorderedApp from "../../BorderedApp" ;
7- import { Dimensions } from "../../../hooks/useDragToResize" ;
7+ import { Dimensions , Position } from "../../../hooks/useDragToResize" ;
88import { MenuItemProps } from "../../MenuItems" ;
99
1010import { StyledIcon , StyledLauncher } from "./styles" ;
11+ import ContextMenu from "../../ContextMenu" ;
1112interface LauncherProps {
1213 windowType : string ;
1314 WindowTitle : string ;
@@ -29,16 +30,31 @@ function Launcher({
2930} : React . PropsWithChildren < LauncherProps > ) {
3031 const winMan = useWindowManagerStore ( ) ;
3132 const ref = useRef < HTMLDivElement > ( null ) ;
33+ const [ contextOpen , setContextOpen ] = useState ( false ) ;
3234
3335 function addWindow ( ) {
3436 const id = windowId ?? uuid ( ) ;
37+ const boundingRect = winMan . contentRef . current ?. getBoundingClientRect ( ) ;
38+ function getInitialPosition ( axis : "x" | "y" ) : number {
39+ if ( ! boundingRect ) return 0 ;
40+ const dimension = axis === "x" ? "width" : "height" ;
41+ return (
42+ ( boundingRect [ axis ] ?? 0 ) +
43+ ( boundingRect [ dimension ] ?? 0 ) / 2 -
44+ initialDimensions [ dimension ] / 2
45+ ) ;
46+ }
3547 winMan . addWindow ( windowType , id , {
3648 component : BorderedApp ,
3749 props : {
3850 id,
3951 title : WindowTitle ,
4052 type : windowType ,
4153 initialDimensions,
54+ initialPosition : {
55+ x : getInitialPosition ( "x" ) ,
56+ y : getInitialPosition ( "y" ) ,
57+ } ,
4258 menus,
4359 } ,
4460 key : id ,
@@ -50,6 +66,7 @@ function Launcher({
5066 // we want to focus them. This means revealing them if they
5167 // are minimized and bring them to the top of the window stack.
5268 if ( winMan . windowsOfTypeExist ( windowType ) ) {
69+ console . log ( "Attempting to focus windows" ) ;
5370 winMan . focusWindowsOfType ( windowType ) ;
5471 return ;
5572 }
@@ -58,10 +75,7 @@ function Launcher({
5875 addWindow ( ) ;
5976 }
6077 function onRightClick ( ) {
61- // TODO: Display a context menu with various options that are
62- // specified by the program-specific launcher and passed via props.
63- // This will include things like "open new window", "close windows", etc.
64- console . log ( "right clicked" ) ;
78+ setContextOpen ( true ) ;
6579 }
6680
6781 useConditionalClick ( {
@@ -76,14 +90,44 @@ function Launcher({
7690 clickHandler : onRightClick ,
7791 } ) ;
7892
93+ function getContextMenu ( ) {
94+ const items : Array < MenuItemProps > = [
95+ {
96+ title : "New Window" ,
97+ action : ( ) => {
98+ addWindow ( ) ;
99+ setContextOpen ( false ) ;
100+ } ,
101+ } ,
102+ ] ;
103+ return (
104+ < ContextMenu
105+ close = { ( ) => setContextOpen ( false ) }
106+ items = { items }
107+ position = { getContextPosition ( items . length ) }
108+ />
109+ ) ;
110+ }
111+ function getContextPosition ( numberOfItems : number ) : Position {
112+ const rect = ref . current ?. getBoundingClientRect ( ) ;
113+ if ( ! rect ) return { x : 0 , y : 0 } ;
114+ console . log ( rect ) ;
115+ return {
116+ x : rect . x ,
117+ y : rect . y - 20 - numberOfItems * 30 ,
118+ } ;
119+ }
79120 return (
80- < StyledLauncher ref = { ref } tabIndex = { 1 } className = "launcher" >
81- < StyledIcon
82- src = { icon }
83- className = "launcher-icon"
84- alt = { windowType }
85- > </ StyledIcon >
86- </ StyledLauncher >
121+ < >
122+ { contextOpen && getContextMenu ( ) }
123+ < StyledLauncher ref = { ref } tabIndex = { 1 } className = "launcher" >
124+ < StyledIcon
125+ src = { icon }
126+ className = "launcher-icon"
127+ alt = { windowType }
128+ > </ StyledIcon >
129+ </ StyledLauncher >
130+ </ >
87131 ) ;
88132}
89133
0 commit comments