Files
FastGPT/projects/app/src/components/MyMenu/index.tsx
Archer 911512b36d 4.7-production (#1053)
* 4.7-alpha3 (#62)

* doc

* Optimize possible null Pointers and parts of Ux

* fix: mulity index training error

* feat: doc and rename question guide

* fix ios speech input (#59)

* fix: prompt editor variables nowrap (#61)

* change openapi import in http module with curl import (#60)

* chore(ui): dataset import modal ui (#58)

* chore(ui): dataset import modal ui

* use component

* fix height

* 4.7 (#63)

* fix: claude3 image type verification failed (#1038) (#1040)

* perf: curl import modal

* doc img

* perf: adapt cohere rerank

* perf: code

* perf: input style

* doc

---------

Co-authored-by: xiaotian <dimsky@163.com>

* fix: ts

* docker deploy

* perf: prompt call

* doc

* ts

* finish ui

* perf: outlink detail ux

* perf: user schema

* fix: plugin update

* feat: get current time plugin

* fix: ts

* perf: fetch anamation

* perf: mark ux

* doc

* perf: select app ux

* fix: split text custom string conflict

* peref: inform readed

* doc

* memo flow component

* perf: version

* faq

* feat: flow max runtimes

* feat: similarity tip

* feat: auto detect file encoding

* Supports asymmetric vector model

* fix: ts

* perf: max w

* move code

* perf: hide whisper

* fix: ts

* feat: system msg modal

* perf: catch error

* perf: inform tip

* fix: inform

---------

Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
Co-authored-by: xiaotian <dimsky@163.com>
2024-03-26 12:09:31 +08:00

136 lines
3.1 KiB
TypeScript

import React, { useRef, useState } from 'react';
import {
Menu,
MenuList,
MenuItem,
Box,
useOutsideClick,
MenuButton,
MenuItemProps
} from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
type MenuItemType = 'primary' | 'danger';
interface Props {
width?: number | string;
offset?: [number, number];
Button: React.ReactNode;
trigger?: 'hover' | 'click';
menuList: {
isActive?: boolean;
label: string | React.ReactNode;
icon?: string;
type?: MenuItemType;
onClick: () => any;
}[];
}
const MyMenu = ({
width = 'auto',
trigger = 'hover',
offset = [0, 5],
Button,
menuList
}: Props) => {
const typeMapStyle: Record<MenuItemType, MenuItemProps> = {
primary: {
_hover: {
backgroundColor: 'primary.50',
color: 'primary.600'
}
},
danger: {
_hover: {
color: 'red.600',
background: 'red.1'
}
}
};
const menuItemStyles: MenuItemProps = {
borderRadius: 'sm',
py: 3,
display: 'flex',
alignItems: 'center'
};
const ref = useRef<HTMLDivElement>(null);
const closeTimer = useRef<any>();
const [isOpen, setIsOpen] = useState(false);
useOutsideClick({
ref: ref,
handler: () => {
setIsOpen(false);
}
});
return (
<Menu offset={offset} isOpen={isOpen} autoSelect={false} direction={'ltr'} isLazy>
<Box
ref={ref}
onMouseEnter={() => {
if (trigger === 'hover') {
setIsOpen(true);
}
clearTimeout(closeTimer.current);
}}
onMouseLeave={() => {
if (trigger === 'hover') {
closeTimer.current = setTimeout(() => {
setIsOpen(false);
}, 100);
}
}}
>
<Box
position={'relative'}
onClickCapture={() => {
if (trigger === 'click') {
setIsOpen(!isOpen);
}
}}
>
<MenuButton
w={'100%'}
h={'100%'}
position={'absolute'}
top={0}
right={0}
bottom={0}
left={0}
/>
<Box position={'relative'}>{Button}</Box>
</Box>
<MenuList
minW={isOpen ? `${width}px !important` : 0}
p={'6px'}
border={'1px solid #fff'}
boxShadow={
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
}
>
{menuList.map((item, i) => (
<MenuItem
key={i}
{...menuItemStyles}
{...typeMapStyle[item.type || 'primary']}
onClick={(e) => {
e.stopPropagation();
setIsOpen(false);
item.onClick && item.onClick();
}}
color={item.isActive ? 'primary.700' : 'myGray.600'}
whiteSpace={'pre-wrap'}
>
{!!item.icon && <MyIcon name={item.icon as any} w={'16px'} mr={2} />}
{item.label}
</MenuItem>
))}
</MenuList>
</Box>
</Menu>
);
};
export default MyMenu;