mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-01 20:56:59 +08:00
feat: HoverPopover done
This commit is contained in:
37
app/components/HoverPopover/index.tsx
Normal file
37
app/components/HoverPopover/index.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||
import { ComponentProps } from "react";
|
||||
|
||||
export interface PopoverProps {
|
||||
content?: JSX.Element | string;
|
||||
children?: JSX.Element;
|
||||
arrowClassName?: string;
|
||||
popoverClassName?: string;
|
||||
noArrow?: boolean;
|
||||
align?: ComponentProps<typeof HoverCard.Content>["align"];
|
||||
}
|
||||
|
||||
export default function HoverPopover(props: PopoverProps) {
|
||||
const {
|
||||
content,
|
||||
children,
|
||||
arrowClassName,
|
||||
popoverClassName,
|
||||
noArrow = false,
|
||||
align,
|
||||
} = props;
|
||||
return (
|
||||
<HoverCard.Root>
|
||||
<HoverCard.Trigger asChild>{children}</HoverCard.Trigger>
|
||||
<HoverCard.Portal>
|
||||
<HoverCard.Content
|
||||
className={`${popoverClassName}`}
|
||||
sideOffset={5}
|
||||
align={align}
|
||||
>
|
||||
{content}
|
||||
{!noArrow && <HoverCard.Arrow className={`${arrowClassName}`} />}
|
||||
</HoverCard.Content>
|
||||
</HoverCard.Portal>
|
||||
</HoverCard.Root>
|
||||
);
|
||||
}
|
@@ -54,6 +54,7 @@ export interface PopoverProps {
|
||||
placement?: "t" | "lt" | "rt" | "lb" | "rb" | "b" | "l" | "r";
|
||||
noArrow?: boolean;
|
||||
delayClose?: number;
|
||||
useGlobalRoot?: boolean;
|
||||
}
|
||||
|
||||
export default function Popover(props: PopoverProps) {
|
||||
@@ -68,6 +69,7 @@ export default function Popover(props: PopoverProps) {
|
||||
placement = "t",
|
||||
noArrow = false,
|
||||
delayClose = 0,
|
||||
useGlobalRoot,
|
||||
} = props;
|
||||
|
||||
const [internalShow, setShow] = useState(false);
|
||||
@@ -244,62 +246,66 @@ export default function Popover(props: PopoverProps) {
|
||||
);
|
||||
}
|
||||
|
||||
// return (
|
||||
// <div
|
||||
// className={`relative ${className}`}
|
||||
// onPointerEnter={(e) => {
|
||||
// e.preventDefault();
|
||||
// clearTimeout(closeTimer.current);
|
||||
// onShow?.(true);
|
||||
// setShow(true);
|
||||
// getRelativePosition(e.currentTarget, "");
|
||||
// window.document.documentElement.style.overflow = "hidden";
|
||||
// }}
|
||||
// onPointerLeave={(e) => {
|
||||
// e.preventDefault();
|
||||
// if (delayClose) {
|
||||
// closeTimer.current = window.setTimeout(() => {
|
||||
// onShow?.(false);
|
||||
// setShow(false);
|
||||
// }, delayClose);
|
||||
// } else {
|
||||
// onShow?.(false);
|
||||
// setShow(false);
|
||||
// }
|
||||
// window.document.documentElement.style.overflow = "auto";
|
||||
// }}
|
||||
// >
|
||||
// {children}
|
||||
// {mergedShow && (
|
||||
// <>
|
||||
// <div
|
||||
// className={`${
|
||||
// noArrow ? "opacity-0" : ""
|
||||
// } bg-inherit ${arrowClassName}`}
|
||||
// style={{ zIndex: baseZIndex + 1 }}
|
||||
// >
|
||||
// <ArrowIcon sibling={popoverRef} />
|
||||
// </div>
|
||||
// {createPortal(
|
||||
// <div
|
||||
// className={` whitespace-nowrap ${popoverCommonClass} ${popoverClassName} cursor-pointer`}
|
||||
// style={{ zIndex: baseZIndex + 1, ...placementStyle }}
|
||||
// ref={popoverRef}
|
||||
// >
|
||||
// {content}
|
||||
// </div>,
|
||||
// popoverRoot,
|
||||
// )}
|
||||
// </>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
if (useGlobalRoot) {
|
||||
return (
|
||||
<div
|
||||
className={`relative ${className}`}
|
||||
onPointerEnter={(e) => {
|
||||
e.preventDefault();
|
||||
clearTimeout(closeTimer.current);
|
||||
onShow?.(true);
|
||||
setShow(true);
|
||||
getRelativePosition(e.currentTarget, "");
|
||||
window.document.documentElement.style.overflow = "hidden";
|
||||
}}
|
||||
onPointerLeave={(e) => {
|
||||
e.preventDefault();
|
||||
if (delayClose) {
|
||||
closeTimer.current = window.setTimeout(() => {
|
||||
onShow?.(false);
|
||||
setShow(false);
|
||||
}, delayClose);
|
||||
} else {
|
||||
onShow?.(false);
|
||||
setShow(false);
|
||||
}
|
||||
window.document.documentElement.style.overflow = "auto";
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
{mergedShow && (
|
||||
<>
|
||||
<div
|
||||
className={`${
|
||||
noArrow ? "opacity-0" : ""
|
||||
} bg-inherit ${arrowClassName}`}
|
||||
style={{ zIndex: baseZIndex + 1 }}
|
||||
>
|
||||
<ArrowIcon sibling={popoverRef} />
|
||||
</div>
|
||||
{createPortal(
|
||||
<div
|
||||
className={` whitespace-nowrap ${popoverCommonClass} ${popoverClassName} cursor-pointer`}
|
||||
style={{ zIndex: baseZIndex + 1, ...placementStyle }}
|
||||
ref={popoverRef}
|
||||
>
|
||||
{content}
|
||||
</div>,
|
||||
popoverRoot,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`group relative ${className}`}
|
||||
onPointerEnter={(e) => {
|
||||
getRelativePosition(e.currentTarget, "");
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@@ -10,9 +10,6 @@ import { showToast } from "@/app/components/ui-lib";
|
||||
import Locale from "@/app/locales";
|
||||
import { Path } from "@/app/constant";
|
||||
|
||||
import LightIcon from "@/app/icons/light.svg";
|
||||
import DarkIcon from "@/app/icons/dark.svg";
|
||||
import AutoIcon from "@/app/icons/auto.svg";
|
||||
import BottomIcon from "@/app/icons/bottom.svg";
|
||||
import StopIcon from "@/app/icons/pause.svg";
|
||||
import RobotIcon from "@/app/icons/robot.svg";
|
||||
|
@@ -23,8 +23,8 @@ import LogIcon from "@/app/icons/logIcon.svg";
|
||||
|
||||
import MenuLayout from "@/app/components/MenuLayout";
|
||||
import Panel from "./ChatPanel";
|
||||
import Popover, { PopoverProps } from "@/app/components/Popover";
|
||||
import Confirm from "@/app/components/Confirm";
|
||||
import HoverPopover from "@/app/components/HoverPopover";
|
||||
|
||||
export function SessionItem(props: {
|
||||
onClick?: () => void;
|
||||
@@ -96,7 +96,7 @@ export function SessionItem(props: {
|
||||
{Locale.ChatItem.ChatItemCount(props.count)}
|
||||
</div>
|
||||
</div>
|
||||
<Popover
|
||||
<HoverPopover
|
||||
content={
|
||||
<div
|
||||
className={`flex items-center gap-3 p-3 rounded-action-btn leading-6 cursor-pointer`}
|
||||
@@ -113,20 +113,17 @@ export function SessionItem(props: {
|
||||
</div>
|
||||
}
|
||||
popoverClassName={`
|
||||
px-2 py-1 border-delete-chat-popover bg-delete-chat-popover-panel rounded-md shadow-delete-chat-popover-shadow
|
||||
px-2 py-1 border-delete-chat-popover bg-delete-chat-popover-panel rounded-md shadow-delete-chat-popover-shadow
|
||||
`}
|
||||
noArrow
|
||||
placement={props.isMobileScreen ? "r" : "l"}
|
||||
className="!absolute top-[50%] translate-y-[-50%] right-3"
|
||||
trigger={props.isMobileScreen ? "click" : "hover"}
|
||||
delayClose={100}
|
||||
align={props.isMobileScreen ? "end" : "start"}
|
||||
>
|
||||
<div
|
||||
className={` pointer-events-none opacity-0 group-hover/chat-menu-list:pointer-events-auto group-hover/chat-menu-list:opacity-100`}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
</Popover>
|
||||
</HoverPopover>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
@@ -175,7 +172,6 @@ export default MenuLayout(function SessionList(props) {
|
||||
<div
|
||||
className={`
|
||||
h-[100%] flex flex-col
|
||||
max-md:pb-chat-panel-mobile
|
||||
md:px-0
|
||||
`}
|
||||
>
|
||||
@@ -213,7 +209,7 @@ export default MenuLayout(function SessionList(props) {
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`flex-1 overflow-y-auto`}
|
||||
className={`flex-1 overflow-y-auto max-md:pb-chat-panel-mobile `}
|
||||
// onClick={(e) => {
|
||||
// if (e.target === e.currentTarget) {
|
||||
// navigate(Path.Home);
|
||||
|
Reference in New Issue
Block a user