Skip to content

Commit

Permalink
Merge pull request #133 from openchatai/fix/falta
Browse files Browse the repository at this point in the history
implem of confirmation message when the user wants to exit the copilo…
  • Loading branch information
faltawy authored Oct 7, 2023
2 parents 9cb04dd + d9e6df9 commit f9a6791
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 37 deletions.
27 changes: 2 additions & 25 deletions copilot-widget/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,15 @@
/>
</head>
<body>
<div class="opencopilot-w-full">
<header
class="opencopilot-w-full opencopilot-shadow-lg opencopilot-flex opencopilot-justify-between opencopilot-items-center"
>
<div
class="opencopilot-container opencopilot-mx-auto opencopilot-px-3 opencopilot-py-5"
>
<div
class="opencopilot-font-sans opencopilot-text-black opencopilot-font-semibold opencopilot-text-lg"
>
Chat bubble
</div>
</div>
<div>
<button id="triggerSelector">toggle the chat widget</button>
</div>
</header>
<div
class="opencopilot-flex opencopilot-items-start opencopilot-gap-1 opencopilot-h-full opencopilot-min-h-full opencopilot-max-h-[80vh]"
>
<main class="opencopilot-flex-1 opencopilot-mt-5">page content</main>
<div id="chat-widget" class="opencopilot-h-full opencopilot-max-h-full"></div>
</div>
</div>
<button id="triggerSelector">toggle the chat widget</button>
<script type="module" src="/src/main.tsx"></script>
<script>
window.onload = () => {
initAiCoPilot({
initialMessage: "Hi Sir",
token: "1RuzS7w5ceGaN6CiK0J7",
triggerSelector: "#triggerSelector",
apiUrl:"https://cloud.openchat.so/api",
apiUrl: "https://cloud.openchat.so/api",
headers: {
Authorization: "Bearer your_auth_token_goes_here",
},
Expand Down
12 changes: 7 additions & 5 deletions copilot-widget/lib/CopilotWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useRef } from "react";
import { useWidgetStateContext } from "./contexts/WidgetState";
import cn from "./utils/cn";
import ChatScreenWithSfxs from "./screens/ChatScreen";
Expand All @@ -10,20 +10,22 @@ export function CopilotWidget({
triggerSelector: string;
}) {
const [open, toggle] = useWidgetStateContext();

useEffect(() => {
if (IS_SERVER) return;
const trigger = document.querySelector(triggerSelector);

if (trigger) {
trigger.addEventListener("click", toggle);

// Return cleanup function to remove event listener
return () => trigger.removeEventListener("click", toggle);
} else {
console.warn(
"the trigger element can't be found,make sure it present in the DOM"
"The trigger element can't be found, make sure it is present in the DOM"
);
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [triggerSelector]);
}, [triggerSelector, toggle]);
return (
<div
className={cn(
Expand Down
42 changes: 38 additions & 4 deletions copilot-widget/lib/components/ChatHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
import { BiX } from "react-icons/bi";
import { useWidgetStateContext } from "../contexts/WidgetState";
import { RxCross2 } from "react-icons/rx";
import {
Dialog,
DialogClose,
DialogContent,
DialogHeader,
DialogTrigger,
} from "./Dialog";

export default function ChatHeader() {
const [,toggle] = useWidgetStateContext()
const [, , SetState] = useWidgetStateContext();
return (
<header className="opencopilot-fade-in-top opencopilot-border-b opencopilot-border-b-black/10 opencopilot-w-full">
<div className="opencopilot-p-3">
<div className="opencopilot-w-full opencopilot-flex opencopilot-items-center opencopilot-justify-between">
<div><h1 className="opencopilot-font-semibold opencopilot-text-sm">OpenPilot</h1></div>
<div>
<h1 className="opencopilot-font-semibold opencopilot-text-sm">
OpenPilot
</h1>
</div>
<div className="opencopilot-flex opencopilot-items-center opencopilot-gap-3">
<button onClick={toggle}><BiX size={19}/></button>
<Dialog>
<DialogTrigger>
<RxCross2 size={19} />
</DialogTrigger>
<DialogContent>
<DialogHeader>Are you sure?</DialogHeader>
<div className="opencopilot-space-y-1">
<DialogClose
onClick={() => {
// Close the widget after 500ms, IDK why but it solves the focus trap issue
setTimeout(() => {
SetState(false);
}, 100);
}}
className="opencopilot-block opencopilot-w-full opencopilot-px-2 opencopilot-text-white opencopilot-shadow opencopilot-py-1 opencopilot-border opencopilot-border-transparent opencopilot-rounded-md opencopilot-bg-rose-500"
>
<span>Exit</span>
</DialogClose>
<DialogClose className="opencopilot-block opencopilot-w-full opencopilot-px-2 opencopilot-shadow opencopilot-py-1 opencopilot-border opencopilot-border-accent2 opencopilot-rounded-md opencopilot-text-black">
<span>Cancel</span>
</DialogClose>
</div>
</DialogContent>
</Dialog>
</div>
</div>
</div>
Expand Down
102 changes: 102 additions & 0 deletions copilot-widget/lib/components/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"use client";

import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import cn from "@lib/utils/cn";
const Dialog = DialogPrimitive.Root;
const DialogClose = DialogPrimitive.Close;
const DialogTrigger = DialogPrimitive.Trigger;

const DialogPortal = DialogPrimitive.Portal;

const DialogOverlay = DialogPrimitive.Overlay;

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogOverlay className="opencopilot-absolute opencopilot-inset-0 opencopilot-z-50 opencopilot-bg-black/50 opencopilot-backdrop-blur-sm data-[state=open]:opencopilot-animate-in data-[state=closed]:opencopilot-animate-out data-[state=closed]:opencopilot-fade-out-0 data-[state=open]:opencopilot-fade-in-0">
<DialogPrimitive.Content
ref={ref}
className={cn(
"opencopilot-rounded-t-lg opencopilot-z-[100] opencopilot-absolute opencopilot-bottom-0 opencopilot-duration-300 opencopilot-w-full opencopilot-grid opencopilot-max-w-lg opencopilot-bg-white opencopilot-gap-4 opencopilot-shadow-lg opencopilot-p-6 opencopilot-animate-in data-[state=closed]:opencopilot-animate-out data-[state=closed]:opencopilot-fade-out-0 data-[state=open]:opencopilot-fade-in-0 data-[state=closed]:slide-out-to-bottom data-[state=open]:opencopilot-slide-in-from-bottom",
className
)}
{...props}
>
{children}
</DialogPrimitive.Content>
</DialogOverlay>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;

const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"opencopilot-flex opencopilot-flex-col opencopilot-space-y-1.5 opencopilot-text-center sm:opencopilot-text-left",
className
)}
{...props}
/>
);
DialogHeader.displayName = "DialogHeader";

const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"opencopilot-flex opencopilot-flex-col-reverse sm:opencopilot-flex-row sm:opencopilot-justify-end sm:opencopilot-space-x-2",
className
)}
{...props}
/>
);
DialogFooter.displayName = "DialogFooter";

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"opencopilot-text-lg opencopilot-font-semibold opencopilot-leading-none opencopilot-tracking-tight",
className
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn(
"opencopilot-text-sm opencopilot-text-muted-foreground",
className
)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

export {
Dialog,
DialogPortal,
DialogOverlay,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
DialogClose,
};
2 changes: 1 addition & 1 deletion copilot-widget/lib/screens/ChatScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function ChatScreen() {
}, [messages, setPos]);

return (
<div className="opencopilot-w-full opencopilot-flex opencopilot-h-full opencopilot-flex-col opencopilot-items-start">
<div className="opencopilot-w-full opencopilot-flex opencopilot-h-full opencopilot-flex-col opencopilot-items-start opencopilot-relative">
<ChatHeader />
<main
ref={scrollElementRef}
Expand Down
1 change: 1 addition & 0 deletions copilot-widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"react-dom": "^18.x"
},
"devDependencies": {
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-popover": "^1.0.6",
"@radix-ui/react-tooltip": "^1.0.6",
"@tailwindcss/typography": "^0.5.9",
Expand Down
106 changes: 106 additions & 0 deletions copilot-widget/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion copilot-widget/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
:root {
--opencopilot-primary-clr: #703ea8;
--opencopilot-accent-clr: #f8f7f8;
--opencopilot-accnet-2-clr: #817f81;
--opencopilot-accent-2-clr: #817f81;
--opencopilot-primary-light-clr: rgba(0, 87, 255, 0.1);
}

Expand Down
Loading

0 comments on commit f9a6791

Please sign in to comment.