Skip to content

Commit 2706d51

Browse files
committed
fix: hot fix for menu items
1 parent c982e30 commit 2706d51

File tree

1 file changed

+33
-9
lines changed
  • apps/frontend/src/components/launches/menu

1 file changed

+33
-9
lines changed

apps/frontend/src/components/launches/menu/menu.tsx

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
'use client';
22

33
import React, {
4-
FC,
5-
MouseEventHandler,
6-
useCallback,
7-
useMemo,
8-
useState,
4+
FC, MouseEventHandler, useCallback, useLayoutEffect, useMemo, useRef, useState
95
} from 'react';
106
import { useClickOutside } from '@mantine/hooks';
117
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
@@ -60,17 +56,39 @@ export const Menu: FC<{
6056
const { integrations, reloadCalendarView } = useCalendar();
6157
const toast = useToaster();
6258
const modal = useModals();
63-
const [show, setShow] = useState(false);
59+
const [show, setShow] = useState<false | {x: number, y: number}>(false);
60+
const menuRef = useRef<HTMLDivElement>(null);
6461
const ref = useClickOutside<HTMLDivElement>(() => {
6562
setShow(false);
6663
});
64+
const showRef = useRef();
65+
66+
// Adjust menu position if it would overflow viewport
67+
useLayoutEffect(() => {
68+
if (show && menuRef.current) {
69+
const menuRect = menuRef.current.getBoundingClientRect();
70+
const viewportHeight = window.innerHeight;
71+
const padding = 10;
72+
73+
// Check if menu overflows bottom of viewport
74+
if (menuRect.bottom > viewportHeight - padding) {
75+
const newY = Math.max(padding, viewportHeight - menuRect.height - padding);
76+
// Only update if position actually changed significantly to avoid infinite loop
77+
if (Math.abs(show.y - newY) > 1) {
78+
setShow(prev => prev ? { ...prev, y: newY } : false);
79+
}
80+
}
81+
}
82+
}, [show]);
6783
const findIntegration: any = useMemo(() => {
6884
return integrations.find((integration) => integration.id === id);
6985
}, [integrations, id]);
7086
const changeShow: MouseEventHandler<HTMLDivElement> = useCallback(
7187
(e) => {
7288
e.stopPropagation();
73-
setShow(!show);
89+
// @ts-ignore
90+
const boundBox = showRef?.current?.getBoundingClientRect();
91+
setShow(show ? false : { x: boundBox?.left, y: boundBox?.top + boundBox?.height });
7492
},
7593
[show]
7694
);
@@ -284,9 +302,10 @@ export const Menu: FC<{
284302
),
285303
});
286304
}, []);
305+
287306
return (
288307
<div
289-
className="cursor-pointer relative select-none"
308+
className="cursor-pointer relative select-none flex"
290309
onClick={changeShow}
291310
ref={ref}
292311
>
@@ -303,10 +322,15 @@ export const Menu: FC<{
303322
fill="currentColor"
304323
/>
305324
</svg>
325+
<div>
326+
<div ref={showRef} />
327+
</div>
306328
{show && (
307329
<div
330+
ref={menuRef}
308331
onClick={(e) => e.stopPropagation()}
309-
className={`absolute top-[100%] start-0 p-[12px] bg-newBgColorInner shadow-menu flex flex-col gap-[16px] z-[100] rounded-[8px] border border-tableBorder text-nowrap`}
332+
style={{left: show.x, top: show.y}}
333+
className={`fixed p-[12px] bg-newBgColorInner shadow-menu flex flex-col gap-[16px] z-[100] rounded-[8px] border border-tableBorder text-nowrap`}
310334
>
311335
{canDisable && !findIntegration?.refreshNeeded && (
312336
<div

0 commit comments

Comments
 (0)