Skip to content

Commit a79e01a

Browse files
authored
Merge pull request #7 from devklick/dev
Dev
2 parents e3b9192 + 7a20cce commit a79e01a

17 files changed

Lines changed: 120 additions & 33 deletions

File tree

src/components/AppSideBar/AppSideBar.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import useSystemSettings from "../../stores/systemSettingsStore";
12
import { StyledItem, StyledItemContainer, StyledSideBar } from "./styles";
23

34
interface SideBarItem {
@@ -11,11 +12,17 @@ interface AppSideBarProps {
1112
}
1213

1314
function AppSideBar({ items }: AppSideBarProps) {
15+
const settings = useSystemSettings();
1416
return (
1517
<StyledSideBar>
1618
<StyledItemContainer>
1719
{items.map((item) => (
18-
<StyledItem onClick={item.onClick} key={item.title}>
20+
<StyledItem
21+
onClick={item.onClick}
22+
key={item.title}
23+
active={item.isActive ?? false}
24+
activeColor={settings.accentColor}
25+
>
1926
{item.title}
2027
</StyledItem>
2128
))}

src/components/AppSideBar/styles.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ export const StyledItemContainer = styled.div`
1111
box-sizing: border-box;
1212
`;
1313

14-
export const StyledItem = styled.div`
14+
export const StyledItem = styled.div<{ active: boolean; activeColor: string }>`
1515
border-radius: 10px;
1616
padding: 6px 10px;
1717
box-sizing: border-box;
1818
box-shadow: 2px 2px 4px rgb(0, 0, 0, 0);
19+
background-color: ${(props) =>
20+
props.active ? props.activeColor : undefined};
1921
&:hover {
20-
backdrop-filter: brightness(150%);
22+
background-color: ${(props) => props.activeColor};
2123
transition: ease-in 0.2s;
2224
}
2325
&:active {

src/components/BorderedApp/BorderedApp.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useRef } from "react";
22
import useWindowManagerStore, {
33
BaseProps,
44
} from "../../stores/windowManagerStore";
5-
import { Dimensions } from "../../hooks/useDragToResize";
5+
import { Dimensions, Position } from "../../hooks/useDragToResize";
66
import BorderedAppMenu from "./BorderedAppMenu/BorderedAppMenu";
77
import usePositionableElement from "../../hooks/usePositionableElement";
88
import useSystemSettings from "../../stores/systemSettingsStore";
@@ -27,6 +27,7 @@ interface BorderedAppProps extends BaseProps {
2727
type: string;
2828
id: string;
2929
initialDimensions: Dimensions;
30+
initialPosition: Position;
3031
maxDimensions?: Dimensions;
3132
minDimensions?: Dimensions;
3233
menus?: Array<MenuItemProps>;
@@ -38,6 +39,7 @@ function BorderedApp({
3839
id,
3940
children,
4041
initialDimensions,
42+
initialPosition,
4143
minDimensions = { height: 350, width: 350 },
4244
menus,
4345
zIndex,
@@ -64,19 +66,22 @@ function BorderedApp({
6466
} = usePositionableElement({
6567
elementRef: appRef,
6668
minDimensions,
69+
initialPosition,
6770
windowType: type,
6871
windowId: id,
6972
});
7073

7174
function onClickClose() {
7275
winMan.closeWindow(type, id);
7376
}
77+
console.log("Bordered app, hidden", String(hidden));
7478

7579
return (
7680
<StyledBorderedApp
7781
ref={appRef}
7882
onMouseDown={() => winMan.focusWindow(type, id)}
7983
initialDimensions={initialDimensions}
84+
initialPosition={initialPosition}
8085
zIndex={zIndex}
8186
backgroundColor={settings.mainColor}
8287
display={hidden === true ? "none" : "grid"}

src/components/BorderedApp/styles.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import styled from "@emotion/styled";
2-
import { Dimensions } from "../../hooks/useDragToResize";
2+
import { Dimensions, Position } from "../../hooks/useDragToResize";
33

44
interface StyledBorderedAppProps {
55
initialDimensions: Dimensions;
6+
initialPosition: Position;
67
zIndex: number | undefined;
78
backgroundColor: string;
89
display: "none" | "grid";
@@ -25,6 +26,8 @@ export const StyledBorderedApp = styled.div<StyledBorderedAppProps>`
2526
z-index: ${(props) => props.zIndex};
2627
background-color: ${(props) => props.backgroundColor};
2728
display: ${(props) => props.display};
29+
left: ${(props) => props.initialPosition.x}px;
30+
top: ${(props) => props.initialPosition.y}px;
2831
`;
2932
export const StyledCorner = styled.div<{
3033
location: "ne" | "se" | "sw" | "nw";

src/components/BottomBar/Launcher/Launcher.tsx

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { useRef } from "react";
1+
import { useRef, useState } from "react";
22
import { v4 as uuid } from "uuid";
33

44
import useConditionalClick from "../../../hooks/useConditionalClick";
55
import useWindowManagerStore from "../../../stores/windowManagerStore";
66
import BorderedApp from "../../BorderedApp";
7-
import { Dimensions } from "../../../hooks/useDragToResize";
7+
import { Dimensions, Position } from "../../../hooks/useDragToResize";
88
import { MenuItemProps } from "../../MenuItems";
99

1010
import { StyledIcon, StyledLauncher } from "./styles";
11+
import ContextMenu from "../../ContextMenu";
1112
interface 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

src/components/ContextMenu/ContextMenu.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import MenuItems, { MenuItemProps } from "../MenuItems";
33
import useDetectMouseDownOutside from "../../hooks/useDetectMouseDownOutside";
44

55
import { StyledContextMenu } from "./styles";
6+
import useBindKeyToAction from "../../hooks/useBindKeyToAction";
67

78
interface ContextMenuProps {
89
items: Array<MenuItemProps>;
@@ -14,6 +15,7 @@ function ContextMenu({ items, position, close }: ContextMenuProps) {
1415
const elementRef = useRef<HTMLDivElement>(null);
1516

1617
useDetectMouseDownOutside({ elementRef, onMouseDown: close });
18+
useBindKeyToAction({ keys: ["Escape"], action: close });
1719

1820
return (
1921
<StyledContextMenu position={position} ref={elementRef}>

src/components/MenuItems/MenuItems.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function MenuItem({
6060
const hoverOpenDelayRef = useRef<NodeJS.Timeout>();
6161
const hoverCloseDelayRef = useRef<NodeJS.Timeout>();
6262
const [open, setOpen] = useState<boolean>(false);
63+
const settings = useSystemSettings();
6364

6465
useEffect(() => {
6566
return () => {
@@ -130,6 +131,7 @@ function MenuItem({
130131
onClick={handleOnClick}
131132
onMouseEnter={handleOnMouseEnter}
132133
onMouseLeave={handleOnMouseLeave}
134+
hoverColor={settings.accentColor}
133135
>
134136
<span>{title}</span>
135137
{items && open && (

src/components/MenuItems/styles.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ export const StyledItemsContent = styled.div`
2222
box-sizing: border-box;
2323
`;
2424

25-
export const StyledMenuItem = styled.div`
25+
export const StyledMenuItem = styled.div<{ hoverColor: string }>`
2626
padding: 5px 12px;
2727
height: 20px;
28+
:hover {
29+
background-color: ${(props) => props.hoverColor};
30+
}
2831
`;

src/hooks/usePositionableElement.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useEffect, useRef } from "react";
2-
import useDragToResize, { Dimensions, Rect } from "./useDragToResize";
2+
import useDragToResize, { Dimensions, Position, Rect } from "./useDragToResize";
33
import useDragToMove from "./useDragToMove";
44
import useWindowMinMax from "./useWindowMinMax";
55

@@ -8,6 +8,7 @@ interface UsePositionableElementProps {
88
minDimensions: Dimensions;
99
windowType: string;
1010
windowId: string;
11+
initialPosition: Position;
1112
}
1213

1314
/**
@@ -21,6 +22,7 @@ function usePositionableElement({
2122
minDimensions,
2223
windowType,
2324
windowId,
25+
initialPosition,
2426
}: UsePositionableElementProps) {
2527
// Hold a single ref for the elements rect,
2628
// so we dont have to call getBoundingClientRect every
@@ -40,11 +42,11 @@ function usePositionableElement({
4042
elementRect.current = {
4143
height: rect.height,
4244
width: rect.width,
43-
left: rect.left,
44-
top: rect.top,
45+
left: initialPosition.x,
46+
top: initialPosition.y,
4547
};
4648
}
47-
}, [elementRef]);
49+
}, [elementRef, initialPosition.x, initialPosition.y]);
4850

4951
// The resize hook allows the app to be resized
5052
// by dragging the corners or edges of the element.

src/hooks/useWindowMinMax.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,11 @@ function useWindowMinMax({
5858
const window = windowRef.current;
5959
if (!window?.style) return;
6060
if (e.target !== window) return;
61+
winMan.hideWindow(windowType, windowId);
6162

62-
window.style.display = "none";
6363
window.style.transition = oldTransition.current;
6464
window.style.transform = oldTransform.current;
6565
window.style.opacity = oldOpacity.current;
66-
winMan.hideWindow(windowType, windowId);
6766
}
6867

6968
useEffect(() => {

0 commit comments

Comments
 (0)