mirror of
https://github.com/QuivrHQ/quivr.git
synced 2024-09-11 14:36:35 +03:00
feat(frontend): helpbox (#3007)
# Description Please include a summary of the changes and the related issue. Please also include relevant motivation and context. ## Checklist before requesting a review Please delete options that are not relevant. - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented hard-to-understand areas - [ ] I have ideally added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged ## Screenshots (if appropriate):
This commit is contained in:
parent
b5f31a83d4
commit
2812ea4f35
@ -18,6 +18,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.blur {
|
||||
filter: opacity(0.1);
|
||||
transition: filter 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.content_container {
|
||||
overflow: scroll;
|
||||
flex: 1 1 0%;
|
||||
|
@ -6,6 +6,7 @@ import { PostHogProvider } from "posthog-js/react";
|
||||
import { PropsWithChildren, useEffect } from "react";
|
||||
|
||||
import { BrainCreationProvider } from "@/lib/components/AddBrainModal/brainCreation-provider";
|
||||
import { HelpWindow } from "@/lib/components/HelpWindow/HelpWindow";
|
||||
import { Menu } from "@/lib/components/Menu/Menu";
|
||||
import { useOutsideClickListener } from "@/lib/components/Menu/hooks/useOutsideClickListener";
|
||||
import { SearchModal } from "@/lib/components/SearchModal/SearchModal";
|
||||
@ -16,6 +17,8 @@ import {
|
||||
} from "@/lib/context";
|
||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||
import { ChatsProvider } from "@/lib/context/ChatsProvider";
|
||||
import { HelpProvider } from "@/lib/context/HelpProvider/help-provider";
|
||||
import { useHelpContext } from "@/lib/context/HelpProvider/hooks/useHelpContext";
|
||||
import { MenuProvider } from "@/lib/context/MenuProvider/Menu-provider";
|
||||
import { useMenuContext } from "@/lib/context/MenuProvider/hooks/useMenuContext";
|
||||
import { NotificationsProvider } from "@/lib/context/NotificationsProvider/notifications-provider";
|
||||
@ -48,6 +51,7 @@ const App = ({ children }: PropsWithChildren): JSX.Element => {
|
||||
const { onClickOutside } = useOutsideClickListener();
|
||||
const { session } = useSupabase();
|
||||
const { isOpened } = useMenuContext();
|
||||
const { isVisible } = useHelpContext();
|
||||
|
||||
usePageTracking();
|
||||
|
||||
@ -66,8 +70,13 @@ const App = ({ children }: PropsWithChildren): JSX.Element => {
|
||||
<IntercomProvider>
|
||||
<div className="flex flex-1 flex-col overflow-auto">
|
||||
<SearchModalProvider>
|
||||
<HelpWindow />
|
||||
<SearchModal />
|
||||
<div className={styles.app_container}>
|
||||
<div
|
||||
className={`${styles.app_container} ${
|
||||
isVisible ? styles.blur : ""
|
||||
}`}
|
||||
>
|
||||
<div className={styles.menu_container}>
|
||||
<Menu />
|
||||
</div>
|
||||
@ -95,25 +104,27 @@ const AppWithQueryClient = ({ children }: PropsWithChildren): JSX.Element => {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<UserSettingsProvider>
|
||||
<BrainProvider>
|
||||
<KnowledgeToFeedProvider>
|
||||
<BrainCreationProvider>
|
||||
<NotificationsProvider>
|
||||
<MenuProvider>
|
||||
<OnboardingProvider>
|
||||
<FromConnectionsProvider>
|
||||
<ChatsProvider>
|
||||
<ChatProvider>
|
||||
<App>{children}</App>
|
||||
</ChatProvider>
|
||||
</ChatsProvider>
|
||||
</FromConnectionsProvider>
|
||||
</OnboardingProvider>
|
||||
</MenuProvider>
|
||||
</NotificationsProvider>
|
||||
</BrainCreationProvider>
|
||||
</KnowledgeToFeedProvider>
|
||||
</BrainProvider>
|
||||
<HelpProvider>
|
||||
<BrainProvider>
|
||||
<KnowledgeToFeedProvider>
|
||||
<BrainCreationProvider>
|
||||
<NotificationsProvider>
|
||||
<MenuProvider>
|
||||
<OnboardingProvider>
|
||||
<FromConnectionsProvider>
|
||||
<ChatsProvider>
|
||||
<ChatProvider>
|
||||
<App>{children}</App>
|
||||
</ChatProvider>
|
||||
</ChatsProvider>
|
||||
</FromConnectionsProvider>
|
||||
</OnboardingProvider>
|
||||
</MenuProvider>
|
||||
</NotificationsProvider>
|
||||
</BrainCreationProvider>
|
||||
</KnowledgeToFeedProvider>
|
||||
</BrainProvider>
|
||||
</HelpProvider>
|
||||
</UserSettingsProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
94
frontend/lib/components/HelpWindow/HelpWindow.module.scss
Normal file
94
frontend/lib/components/HelpWindow/HelpWindow.module.scss
Normal file
@ -0,0 +1,94 @@
|
||||
@use "styles/BoxShadow.module.scss";
|
||||
@use "styles/ScreenSizes.module.scss";
|
||||
@use "styles/Spacings.module.scss";
|
||||
@use "styles/Typography.module.scss";
|
||||
@use "styles/ZIndexes.module.scss";
|
||||
|
||||
.help_wrapper {
|
||||
position: absolute;
|
||||
height: 100vh;
|
||||
right: 0;
|
||||
width: 0;
|
||||
z-index: ZIndexes.$modal + 1;
|
||||
box-shadow: BoxShadow.$medium;
|
||||
background-color: var(--background-0);
|
||||
overflow: hidden;
|
||||
transition: width 0.2s ease-in-out;
|
||||
overflow-y: auto;
|
||||
|
||||
&.visible {
|
||||
width: 600px;
|
||||
|
||||
.header {
|
||||
display: block;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: Spacings.$spacing05;
|
||||
border-bottom: 1px solid var(--border-1);
|
||||
|
||||
.title {
|
||||
@include Typography.H1;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: Spacings.$spacing05;
|
||||
display: block;
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
@include Typography.H2;
|
||||
}
|
||||
|
||||
.section_content {
|
||||
padding: Spacings.$spacing05;
|
||||
padding-inline: Spacings.$spacing06;
|
||||
font-size: Typography.$small;
|
||||
|
||||
ul {
|
||||
padding: Spacings.$spacing05;
|
||||
li {
|
||||
padding-block: Spacings.$spacing03;
|
||||
|
||||
.connection {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: Spacings.$spacing02;
|
||||
padding-right: Spacings.$spacing02;
|
||||
|
||||
.pre {
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding-top: Spacings.$spacing05;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: ScreenSizes.$small) {
|
||||
&.visible {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
188
frontend/lib/components/HelpWindow/HelpWindow.tsx
Normal file
188
frontend/lib/components/HelpWindow/HelpWindow.tsx
Normal file
@ -0,0 +1,188 @@
|
||||
import Image from "next/image";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { useUserApi } from "@/lib/api/user/useUserApi";
|
||||
import { useHelpContext } from "@/lib/context/HelpProvider/hooks/useHelpContext";
|
||||
import { useUserData } from "@/lib/hooks/useUserData";
|
||||
|
||||
import styles from "./HelpWindow.module.scss";
|
||||
|
||||
import { Icon } from "../ui/Icon/Icon";
|
||||
|
||||
export const HelpWindow = (): JSX.Element => {
|
||||
const { isVisible, setIsVisible } = useHelpContext();
|
||||
const [loadingOnboarded, setLoadingOnboarded] = useState(false);
|
||||
const helpWindowRef = useRef<HTMLDivElement>(null);
|
||||
const { userIdentityData } = useUserData();
|
||||
const { updateUserIdentity } = useUserApi();
|
||||
|
||||
const closeHelpWindow = async () => {
|
||||
setIsVisible(false);
|
||||
if (!userIdentityData?.onboarded) {
|
||||
setLoadingOnboarded(true);
|
||||
await updateUserIdentity({
|
||||
...userIdentityData,
|
||||
username: userIdentityData?.username ?? "",
|
||||
onboarded: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
userIdentityData?.username &&
|
||||
!userIdentityData.onboarded &&
|
||||
!loadingOnboarded
|
||||
) {
|
||||
setIsVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
helpWindowRef.current &&
|
||||
!helpWindowRef.current.contains(event.target as Node)
|
||||
) {
|
||||
void (async () => {
|
||||
try {
|
||||
await closeHelpWindow();
|
||||
} catch (error) {
|
||||
console.error("Error while closing help window", error);
|
||||
}
|
||||
})();
|
||||
} else {
|
||||
setIsVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${styles.help_wrapper} ${isVisible ? styles.visible : ""}`}
|
||||
ref={helpWindowRef}
|
||||
>
|
||||
<div className={styles.header}>
|
||||
<span className={styles.title}>🧠 What is Quivr ?</span>
|
||||
<Icon
|
||||
name="close"
|
||||
size="normal"
|
||||
color="black"
|
||||
handleHover={true}
|
||||
onClick={() => closeHelpWindow()}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.section}>
|
||||
<span className={styles.title}>🧱 Build your second brains</span>
|
||||
<span className={styles.section_content}>
|
||||
A <strong>Brain</strong> in Quivr is an advanced knowledge system
|
||||
designed to integrate and leverage information from various sources.
|
||||
<ul>
|
||||
<li>
|
||||
<strong>📁 Knowledge Integration</strong>
|
||||
<br /> Connect to and pull data from various platforms like{" "}
|
||||
<span className={styles.connection}>
|
||||
<strong>Google Drive</strong>{" "}
|
||||
<Image
|
||||
src="https://quivr-cms.s3.eu-west-3.amazonaws.com/gdrive_8316d080fd.png"
|
||||
alt="Google Drive"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
</span>
|
||||
,
|
||||
<span className={styles.connection}>
|
||||
<strong>SharePoint</strong>{" "}
|
||||
<Image
|
||||
src="https://quivr-cms.s3.eu-west-3.amazonaws.com/sharepoint_8c41cfdb09.png"
|
||||
alt="SharePoint"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
</span>
|
||||
, and{""}
|
||||
<span className={styles.connection}>
|
||||
<strong className={styles.pre}> Dropbox</strong>{" "}
|
||||
<Image
|
||||
src="https://quivr-cms.s3.eu-west-3.amazonaws.com/dropbox_dce4f3d753.png"
|
||||
alt="Dropbox"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
</span>
|
||||
. You can also incorporate data from <strong>URLs</strong> and{" "}
|
||||
<strong>files</strong>.
|
||||
</li>
|
||||
<li>
|
||||
<strong>🤖 AI Models</strong>
|
||||
<br /> Utilize powerful models such as{" "}
|
||||
<strong>
|
||||
<em>GPT</em>
|
||||
</strong>{" "}
|
||||
and{" "}
|
||||
<strong>
|
||||
<em>Mistral</em>
|
||||
</strong>{" "}
|
||||
to process and understand the integrated knowledge.
|
||||
</li>
|
||||
<li>
|
||||
<strong>🔧 Customization</strong>
|
||||
<br /> Tailor the behavior of your Brain with{" "}
|
||||
<em>custom prompts</em> and <em>settings</em>, such as{" "}
|
||||
<strong>max tokens</strong>, to better suit your needs.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
You can also <strong>share</strong> your brains with other Quivr
|
||||
users, allowing them to access and benefit from your knowledge
|
||||
systems. 🤝
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.section}>
|
||||
<span className={styles.title}>🤖 Talk to AI Models</span>
|
||||
<span className={styles.section_content}>
|
||||
<p>
|
||||
Quivr allows you to <strong>interact directly</strong> with AI
|
||||
models such as{" "}
|
||||
<strong>
|
||||
<em>GPT-4</em>
|
||||
</strong>{" "}
|
||||
and{" "}
|
||||
<strong>
|
||||
<em>Mistral</em>
|
||||
</strong>
|
||||
. Simply start a conversation with the AI to get answers and
|
||||
support based on a broad range of data and knowledge. 🤖✨
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.section}>
|
||||
<div className={styles.title}>🎯 Select assistant</div>
|
||||
<span className={styles.section_content}>
|
||||
<p>
|
||||
Press
|
||||
<strong> @</strong> to choose the AI model or the Brain you want
|
||||
to interact with.
|
||||
</p>
|
||||
</span>
|
||||
<div className={styles.image}>
|
||||
<Image
|
||||
src="https://quivr-cms.s3.eu-west-3.amazonaws.com/Screen_82ac3783aa.png"
|
||||
width={500}
|
||||
height={100}
|
||||
alt="Quivr"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,3 +1,4 @@
|
||||
@use "styles/Radius.module.scss";
|
||||
@use "styles/ScreenSizes.module.scss";
|
||||
@use "styles/Spacings.module.scss";
|
||||
@use "styles/Typography.module.scss";
|
||||
@ -40,3 +41,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.help_button {
|
||||
display: flex;
|
||||
padding: Spacings.$spacing02;
|
||||
position: absolute;
|
||||
top: Spacings.$spacing04;
|
||||
right: Spacings.$spacing03;
|
||||
border-radius: Radius.$circle;
|
||||
cursor: pointer;
|
||||
background-color: var(--background-2);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--background-3);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useHelpContext } from "@/lib/context/HelpProvider/hooks/useHelpContext";
|
||||
import { useMenuContext } from "@/lib/context/MenuProvider/hooks/useMenuContext";
|
||||
import { ButtonType } from "@/lib/types/QuivrButton";
|
||||
|
||||
@ -18,28 +19,39 @@ export const PageHeader = ({
|
||||
buttons,
|
||||
}: Props): JSX.Element => {
|
||||
const { isOpened } = useMenuContext();
|
||||
const { isVisible, setIsVisible } = useHelpContext();
|
||||
|
||||
return (
|
||||
<div className={styles.page_header_wrapper}>
|
||||
<div className={`${styles.left} ${!isOpened ? styles.menu_closed : ""}`}>
|
||||
<Icon name={iconName} size="large" color="primary" />
|
||||
<span>{label}</span>
|
||||
<>
|
||||
<div className={styles.page_header_wrapper}>
|
||||
<div
|
||||
className={`${styles.left} ${!isOpened ? styles.menu_closed : ""}`}
|
||||
>
|
||||
<Icon name={iconName} size="large" color="primary" />
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
<div className={styles.buttons_wrapper}>
|
||||
{buttons.map((button, index) => (
|
||||
<QuivrButton
|
||||
key={index}
|
||||
label={button.label}
|
||||
onClick={button.onClick}
|
||||
color={button.color}
|
||||
iconName={button.iconName}
|
||||
hidden={button.hidden}
|
||||
disabled={button.disabled}
|
||||
tooltip={button.tooltip}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.buttons_wrapper}>
|
||||
{buttons.map((button, index) => (
|
||||
<QuivrButton
|
||||
key={index}
|
||||
label={button.label}
|
||||
onClick={button.onClick}
|
||||
color={button.color}
|
||||
iconName={button.iconName}
|
||||
hidden={button.hidden}
|
||||
disabled={button.disabled}
|
||||
tooltip={button.tooltip}
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className={styles.help_button}
|
||||
onClick={() => setIsVisible(!isVisible)}
|
||||
>
|
||||
<Icon name="help" size="normal" color="black" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
29
frontend/lib/context/HelpProvider/help-provider.tsx
Normal file
29
frontend/lib/context/HelpProvider/help-provider.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { createContext, useState } from "react";
|
||||
|
||||
type HelpContextType = {
|
||||
isVisible: boolean;
|
||||
setIsVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
export const HelpContext = createContext<HelpContextType | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
export const HelpProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}): JSX.Element => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<HelpContext.Provider
|
||||
value={{
|
||||
isVisible,
|
||||
setIsVisible,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</HelpContext.Provider>
|
||||
);
|
||||
};
|
13
frontend/lib/context/HelpProvider/hooks/useHelpContext.tsx
Normal file
13
frontend/lib/context/HelpProvider/hooks/useHelpContext.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { useContext } from "react";
|
||||
|
||||
import { HelpContext } from "../help-provider";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export const useHelpContext = () => {
|
||||
const context = useContext(HelpContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("useHelpContext must be used within a HelpProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
@ -7,7 +7,7 @@ export const useNotificationsContext = () => {
|
||||
const context = useContext(NotificationsContext);
|
||||
if (context === undefined) {
|
||||
throw new Error(
|
||||
"useNotificationsContext must be used within a MenuProvider"
|
||||
"useNotificationsContext must be used within a NotificationsProvider"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@ import { GoLightBulb } from "react-icons/go";
|
||||
import { HiBuildingOffice } from "react-icons/hi2";
|
||||
import {
|
||||
IoIosAdd,
|
||||
IoIosHelpCircleOutline,
|
||||
IoIosRadio,
|
||||
IoMdClose,
|
||||
IoMdLogOut,
|
||||
@ -59,6 +58,7 @@ import {
|
||||
IoBookOutline,
|
||||
IoCloudDownloadOutline,
|
||||
IoFootsteps,
|
||||
IoHelp,
|
||||
IoHomeOutline,
|
||||
IoShareSocial,
|
||||
IoWarningOutline,
|
||||
@ -146,7 +146,7 @@ export const iconList: { [name: string]: IconType } = {
|
||||
goal: LuGoal,
|
||||
graph: VscGraph,
|
||||
hashtag: RiHashtag,
|
||||
help: IoIosHelpCircleOutline,
|
||||
help: IoHelp,
|
||||
hide: LuArrowLeftFromLine,
|
||||
history: MdHistory,
|
||||
home: IoHomeOutline,
|
||||
|
Loading…
Reference in New Issue
Block a user