mirror of
https://github.com/StanGirard/quivr.git
synced 2024-09-11 13:15:41 +03:00
feat(panel): added (#2088)
# 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
63c27975f5
commit
66ffc6b9aa
@ -11,7 +11,7 @@ const BrainsManagement = (): JSX.Element => {
|
||||
const { t } = useTranslation("chat");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col flex-1 bg-highlight">
|
||||
<div className="flex flex-col flex-1 bg-white">
|
||||
<div className="w-full h-full p-6 flex flex-col flex-1 overflow-auto">
|
||||
<div className="w-full mb-10">
|
||||
<div className="flex flex-row justify-center items-center gap-2">
|
||||
|
@ -0,0 +1,7 @@
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
|
||||
.data_panel_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: Spacings.$spacing05;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useChatContext } from "@/lib/context";
|
||||
import { CloseBrain } from "@/lib/types/MessageMetadata";
|
||||
|
||||
import styles from "./DataPanel.module.scss";
|
||||
import RelatedBrains from "./components/RelatedBrains/RelatedBrains";
|
||||
|
||||
const DataPanel = (): JSX.Element => {
|
||||
const { messages } = useChatContext();
|
||||
const [lastMessageRelatedBrain, setLastMessageRelatedBrain] = useState<
|
||||
CloseBrain[]
|
||||
>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (messages.length > 0) {
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
if (lastMessage?.metadata?.close_brains) {
|
||||
setLastMessageRelatedBrain(lastMessage.metadata.close_brains);
|
||||
}
|
||||
}
|
||||
}, [lastMessageRelatedBrain, messages]);
|
||||
|
||||
return (
|
||||
<div className={styles.data_panel_wrapper}>
|
||||
<RelatedBrains closeBrains={lastMessageRelatedBrain} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataPanel;
|
@ -0,0 +1,50 @@
|
||||
@use "@/styles/Colors.module.scss";
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
|
||||
.close_brains_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: Spacings.$spacing03;
|
||||
gap: Spacings.$spacing01;
|
||||
|
||||
.brain_line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-left: Spacings.$spacing03;
|
||||
padding-right: Spacings.$spacing05;
|
||||
overflow: hidden;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: Spacings.$spacing03;
|
||||
|
||||
.copy_icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.brain_name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&.current {
|
||||
color: Colors.$primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.similarity_score {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.left .copy_icon {
|
||||
visibility: visible;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { FoldableSection } from "@/lib/components/ui/FoldableSection/FoldableSection";
|
||||
import Icon from "@/lib/components/ui/Icon/Icon";
|
||||
import { useChatContext } from "@/lib/context";
|
||||
import { CloseBrain } from "@/lib/types/MessageMetadata";
|
||||
|
||||
import styles from "./RelatedBrains.module.scss";
|
||||
|
||||
interface RelatedBrainsProps {
|
||||
closeBrains: CloseBrain[];
|
||||
}
|
||||
|
||||
interface CloseBrainProps {
|
||||
color: string;
|
||||
isCurrentBrain: boolean;
|
||||
}
|
||||
|
||||
const RelatedBrains = ({ closeBrains }: RelatedBrainsProps): JSX.Element => {
|
||||
const [closeBrainsProps, setCloseBrainProps] = useState<CloseBrainProps[]>(
|
||||
[]
|
||||
);
|
||||
const { messages } = useChatContext();
|
||||
const lerp = (start: number, end: number, t: number): number => {
|
||||
return start * (1 - t) + end * t;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const newProps = closeBrains.map((brain) => {
|
||||
const t = Math.pow(brain.similarity, 2);
|
||||
const r = Math.round(lerp(211, 138, t));
|
||||
const g = Math.round(lerp(211, 43, t));
|
||||
const b = Math.round(lerp(211, 226, t));
|
||||
const isCurrentBrain =
|
||||
brain.name === messages[messages.length - 1].brain_name;
|
||||
|
||||
return { color: `rgb(${r}, ${g}, ${b})`, isCurrentBrain: isCurrentBrain };
|
||||
});
|
||||
setCloseBrainProps(newProps);
|
||||
}, [closeBrains, messages]);
|
||||
|
||||
if (closeBrains.length === 0) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<FoldableSection
|
||||
label="Related Brains (Beta)"
|
||||
icon="brain"
|
||||
foldedByDefault={true}
|
||||
>
|
||||
<div className={styles.close_brains_wrapper}>
|
||||
{closeBrains.map((brain, index) => (
|
||||
<div className={styles.brain_line} key={index}>
|
||||
<div className={styles.left}>
|
||||
<div className={styles.copy_icon}>
|
||||
<Icon
|
||||
name="copy"
|
||||
size="normal"
|
||||
color="black"
|
||||
handleHover={true}
|
||||
onClick={() =>
|
||||
void navigator.clipboard.writeText("@" + brain.name)
|
||||
}
|
||||
></Icon>
|
||||
</div>
|
||||
<p
|
||||
className={`
|
||||
${styles.brain_name ?? ""}
|
||||
${
|
||||
closeBrainsProps[index]?.isCurrentBrain
|
||||
? styles.current ?? ""
|
||||
: ""
|
||||
}
|
||||
`}
|
||||
>
|
||||
@{brain.name}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={styles.similarity_score}
|
||||
title="Similarity score"
|
||||
style={{ color: closeBrainsProps[index]?.color }}
|
||||
>
|
||||
{Math.round(brain.similarity * 100)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</FoldableSection>
|
||||
);
|
||||
};
|
||||
|
||||
export default RelatedBrains;
|
@ -83,7 +83,7 @@ export const useChat = () => {
|
||||
}
|
||||
|
||||
const chatQuestion: ChatQuestion = {
|
||||
model,
|
||||
model, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
|
||||
question,
|
||||
temperature: temperature,
|
||||
max_tokens: maxTokens,
|
||||
@ -93,7 +93,6 @@ export const useChat = () => {
|
||||
|
||||
callback?.();
|
||||
await addStreamQuestion(currentChatId, chatQuestion);
|
||||
|
||||
} catch (error) {
|
||||
console.error({ error });
|
||||
|
||||
|
20
frontend/app/chat/[chatId]/page.module.scss
Normal file
20
frontend/app/chat/[chatId]/page.module.scss
Normal file
@ -0,0 +1,20 @@
|
||||
@use "@/styles/Colors.module.scss";
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
|
||||
.chat_page_container {
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
background-color: Colors.$white;
|
||||
padding: Spacings.$spacing06;
|
||||
display: flex;
|
||||
gap: Spacings.$spacing09;
|
||||
|
||||
&.feeding {
|
||||
background-color: Colors.$chat-bg-gray;
|
||||
}
|
||||
|
||||
.data_panel_wrapper {
|
||||
height: 100%;
|
||||
width: 30%;
|
||||
}
|
||||
}
|
@ -1,41 +1,54 @@
|
||||
"use client";
|
||||
|
||||
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||
import { useDevice } from "@/lib/hooks/useDevice";
|
||||
import { useCustomDropzone } from "@/lib/hooks/useDropzone";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { ActionsBar } from "./components/ActionsBar";
|
||||
import { ChatDialogueArea } from "./components/ChatDialogueArea/ChatDialogue";
|
||||
import DataPanel from "./components/DataPanel/DataPanel";
|
||||
import { useChatNotificationsSync } from "./hooks/useChatNotificationsSync";
|
||||
import styles from "./page.module.scss";
|
||||
|
||||
const SelectedChatPage = (): JSX.Element => {
|
||||
const { getRootProps } = useCustomDropzone();
|
||||
const { shouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||
const { getRootProps } = useCustomDropzone();
|
||||
const { shouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||
const { isMobile } = useDevice();
|
||||
|
||||
useChatNotificationsSync();
|
||||
useChatNotificationsSync();
|
||||
|
||||
return (
|
||||
<div className="flex flex-1">
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col flex-1 items-center justify-stretch w-full h-full overflow-hidden",
|
||||
shouldDisplayFeedCard ? "bg-chat-bg-gray" : "bg-ivory",
|
||||
"dark:bg-black transition-colors ease-out duration-500"
|
||||
)}
|
||||
data-testid="chat-page"
|
||||
{...getRootProps()}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col flex-1 w-full max-w-4xl h-full dark:shadow-primary/25 overflow-hidden p-2 sm:p-4 md:p-6 lg:p-8`}
|
||||
>
|
||||
<div className="flex flex-1 flex-col overflow-y-auto">
|
||||
<ChatDialogueArea />
|
||||
</div>
|
||||
<ActionsBar />
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
${styles.chat_page_container ?? ""}
|
||||
${shouldDisplayFeedCard ? styles.feeding ?? "" : ""}
|
||||
`}
|
||||
data-testid="chat-page"
|
||||
{...getRootProps()}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col flex-1 items-center justify-stretch w-full h-full overflow-hidden",
|
||||
"dark:bg-black transition-colors ease-out duration-500"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col flex-1 w-full max-w-4xl h-full dark:shadow-primary/25 overflow-hidden`}
|
||||
>
|
||||
<div className="flex flex-1 flex-col overflow-y-auto">
|
||||
<ChatDialogueArea />
|
||||
</div>
|
||||
<ActionsBar />
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
{!isMobile && (
|
||||
<div className={styles.data_panel_wrapper}>
|
||||
<DataPanel />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectedChatPage;
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { UUID } from "crypto";
|
||||
|
||||
import { CloseBrain } from "@/lib/types/MessageMetadata";
|
||||
|
||||
export type ChatQuestion = {
|
||||
model?: string;
|
||||
question?: string;
|
||||
@ -18,6 +20,7 @@ export type ChatMessage = {
|
||||
brain_name?: string;
|
||||
metadata?: {
|
||||
sources?: [string];
|
||||
close_brains?: CloseBrain[];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
@use "@/styles/Variables.module.scss";
|
||||
|
||||
.search_page_container {
|
||||
background-color: Colors.$ivory;
|
||||
background-color: Colors.$white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
@ -5,7 +5,7 @@ import { MenuControlButton } from "@/app/chat/[chatId]/components/ActionsBar/com
|
||||
import { nonProtectedPaths } from "@/lib/config/routesConfig";
|
||||
import { useMenuContext } from "@/lib/context/MenuProvider/hooks/useMenuContext";
|
||||
|
||||
import styles from './Menu.module.scss'
|
||||
import styles from "./Menu.module.scss";
|
||||
import { AnimatedDiv } from "./components/AnimationDiv";
|
||||
import { BrainsManagementButton } from "./components/BrainsManagementButton";
|
||||
import { DiscussionButton } from "./components/DiscussionButton";
|
||||
@ -16,51 +16,58 @@ import { ProfileButton } from "./components/ProfileButton";
|
||||
import { UpgradeToPlus } from "./components/UpgradeToPlus";
|
||||
|
||||
export const Menu = (): JSX.Element => {
|
||||
const { isOpened } = useMenuContext();
|
||||
const pathname = usePathname() ?? "";
|
||||
const { isOpened } = useMenuContext();
|
||||
const pathname = usePathname() ?? "";
|
||||
|
||||
if (nonProtectedPaths.includes(pathname)) {
|
||||
return <></>;
|
||||
}
|
||||
if (nonProtectedPaths.includes(pathname)) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const displayedOnPages = ["/chat", "/library", "/brains-management", "/search"];
|
||||
const displayedOnPages = [
|
||||
"/chat",
|
||||
"/library",
|
||||
"/brains-management",
|
||||
"/search",
|
||||
];
|
||||
|
||||
const isMenuDisplayed = displayedOnPages.some((page) =>
|
||||
pathname.includes(page)
|
||||
);
|
||||
const isMenuDisplayed = displayedOnPages.some((page) =>
|
||||
pathname.includes(page)
|
||||
);
|
||||
|
||||
if (!isMenuDisplayed) {
|
||||
return <></>;
|
||||
}
|
||||
if (!isMenuDisplayed) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
|
||||
return (
|
||||
<MotionConfig transition={{ mass: 1, damping: 10, duration: 0.2 }}>
|
||||
<div
|
||||
className="flex flex-col fixed sm:sticky top-0 left-0 h-full overflow-visible z-[1000] border-r border-black/10 dark:border-white/25 bg-highlight"
|
||||
>
|
||||
<AnimatedDiv>
|
||||
<div className="flex flex-col flex-1 p-4 gap-4 h-full">
|
||||
<MenuHeader />
|
||||
<div className="flex flex-1 w-full">
|
||||
<div className="w-full gap-2 flex flex-col">
|
||||
<DiscussionButton />
|
||||
<ExplorerButton />
|
||||
<BrainsManagementButton />
|
||||
<ParametersButton />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<UpgradeToPlus />
|
||||
<ProfileButton />
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedDiv>
|
||||
return (
|
||||
<MotionConfig transition={{ mass: 1, damping: 10, duration: 0.2 }}>
|
||||
<div className="flex flex-col fixed sm:sticky top-0 left-0 h-full overflow-visible z-[1000] border-r border-black/10 dark:border-white/25 bg-highlight">
|
||||
<AnimatedDiv>
|
||||
<div className="flex flex-col flex-1 p-4 gap-4 h-full">
|
||||
<MenuHeader />
|
||||
<div className="flex flex-1 w-full">
|
||||
<div className="w-full gap-2 flex flex-col">
|
||||
<DiscussionButton />
|
||||
<ExplorerButton />
|
||||
<BrainsManagementButton />
|
||||
<ParametersButton />
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${styles.menu_control_button_wrapper} ${isOpened ? styles.shifted : ''}`}>
|
||||
<MenuControlButton />
|
||||
<div>
|
||||
<UpgradeToPlus />
|
||||
<ProfileButton />
|
||||
</div>
|
||||
</MotionConfig>
|
||||
);
|
||||
</div>
|
||||
</AnimatedDiv>
|
||||
</div>
|
||||
<div
|
||||
className={`${styles.menu_control_button_wrapper} ${
|
||||
isOpened ? styles.shifted : ""
|
||||
}`}
|
||||
>
|
||||
<MenuControlButton />
|
||||
</div>
|
||||
</MotionConfig>
|
||||
);
|
||||
};
|
||||
|
@ -21,7 +21,7 @@ export const AnimatedDiv = ({ children }: AnimatedDivProps): JSX.Element => {
|
||||
? "10px 10px 16px rgba(0, 0, 0, 0)"
|
||||
: "10px 10px 16px rgba(0, 0, 0, 0.5)",
|
||||
}}
|
||||
className={"overflow-hidden flex flex-col flex-1 bg-white"}
|
||||
className={"overflow-hidden flex flex-col flex-1 bg-grey"}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
|
@ -0,0 +1,36 @@
|
||||
@use "@/styles/Colors.module.scss";
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
|
||||
.foldable_section_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 5px;
|
||||
border: 1px dashed Colors.$light-grey;
|
||||
overflow: hidden;
|
||||
|
||||
.header_wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: Spacings.$spacing03;
|
||||
|
||||
.header_left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: Spacings.$spacing03;
|
||||
overflow: hidden;
|
||||
|
||||
.header_title {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: Colors.$lightest-grey;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { iconList } from "@/lib/helpers/iconList";
|
||||
|
||||
import styles from "./FoldableSection.module.scss";
|
||||
|
||||
import { Icon } from "../Icon/Icon";
|
||||
|
||||
interface FoldableSectionProps {
|
||||
label: string;
|
||||
icon: keyof typeof iconList;
|
||||
children: React.ReactNode;
|
||||
foldedByDefault?: boolean;
|
||||
}
|
||||
|
||||
export const FoldableSection = (props: FoldableSectionProps): JSX.Element => {
|
||||
const [folded, setFolded] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
setFolded(props.foldedByDefault ?? false);
|
||||
}, [props.foldedByDefault]);
|
||||
|
||||
return (
|
||||
<div className={styles.foldable_section_wrapper}>
|
||||
<div className={styles.header_wrapper} onClick={() => setFolded(!folded)}>
|
||||
<div className={styles.header_left}>
|
||||
<Icon name={props.icon} size="normal" color="black" />
|
||||
<p className={styles.header_title}>{props.label}</p>
|
||||
</div>
|
||||
<Icon
|
||||
name={folded ? "chevronDown" : "chevronRight"}
|
||||
size="large"
|
||||
color="accent"
|
||||
/>
|
||||
</div>
|
||||
{!folded && <div>{props.children}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -25,7 +25,7 @@
|
||||
color: Colors.$black;
|
||||
|
||||
&.hovered {
|
||||
color: Colors.$accent;
|
||||
color: Colors.$primary;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { IconType } from "react-icons/lib";
|
||||
|
||||
import { iconList } from "@/lib/helpers/iconList";
|
||||
@ -13,6 +14,8 @@ interface IconProps {
|
||||
disabled?: boolean;
|
||||
classname?: string;
|
||||
hovered?: boolean;
|
||||
handleHover?: boolean;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const Icon = ({
|
||||
@ -22,9 +25,18 @@ export const Icon = ({
|
||||
disabled,
|
||||
classname,
|
||||
hovered,
|
||||
handleHover,
|
||||
onClick,
|
||||
}: IconProps): JSX.Element => {
|
||||
const [iconHovered, setIconHovered] = useState(false);
|
||||
const IconComponent: IconType = iconList[name];
|
||||
|
||||
useEffect(() => {
|
||||
if (!handleHover) {
|
||||
setIconHovered(!!hovered);
|
||||
}
|
||||
}, [hovered, handleHover]);
|
||||
|
||||
return (
|
||||
<IconComponent
|
||||
className={`
|
||||
@ -32,8 +44,11 @@ export const Icon = ({
|
||||
${styles[size] ?? ""}
|
||||
${styles[color] ?? ""}
|
||||
${disabled ? styles.disabled ?? "" : ""}
|
||||
${hovered ? styles.hovered ?? "" : ""}
|
||||
${iconHovered ? styles.hovered ?? "" : ""}
|
||||
`}
|
||||
onMouseEnter={() => handleHover && setIconHovered(true)}
|
||||
onMouseLeave={() => handleHover && setIconHovered(false)}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -10,12 +10,7 @@
|
||||
background-color: Colors.$white;
|
||||
padding: Spacings.$spacing05;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
|
||||
0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
border: 1px solid Colors.$light-grey;
|
||||
|
||||
.search_icon {
|
||||
width: IconSizes.$big;
|
||||
|
@ -13,6 +13,6 @@
|
||||
color: Colors.$black;
|
||||
|
||||
&.hovered {
|
||||
color: Colors.$accent;
|
||||
color: Colors.$primary;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,20 @@
|
||||
import { AiOutlineLoading3Quarters } from "react-icons/ai";
|
||||
import { IconType } from "react-icons/lib";
|
||||
import { LuPlusCircle, LuSearch } from "react-icons/lu";
|
||||
import {
|
||||
LuBrain,
|
||||
LuChevronDown,
|
||||
LuChevronRight,
|
||||
LuCopy,
|
||||
LuPlusCircle,
|
||||
LuSearch,
|
||||
} from "react-icons/lu";
|
||||
|
||||
export const iconList: { [name: string]: IconType } = {
|
||||
add: LuPlusCircle,
|
||||
brain: LuBrain,
|
||||
chevronDown: LuChevronDown,
|
||||
chevronRight: LuChevronRight,
|
||||
copy: LuCopy,
|
||||
loader: AiOutlineLoading3Quarters,
|
||||
search: LuSearch,
|
||||
};
|
||||
|
9
frontend/lib/types/MessageMetadata.ts
Normal file
9
frontend/lib/types/MessageMetadata.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface CloseBrain {
|
||||
id: string;
|
||||
similarity: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface MessageMetadata {
|
||||
closeBrains: CloseBrain[];
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
$white: #FFFFFF;
|
||||
$black: #11243E;
|
||||
$primary: #6142D4;
|
||||
$secondary: #F3ECFF;
|
||||
$tertiary: #F6F4FF;
|
||||
$accent: #13ABBA;
|
||||
$highlight: #FAFAFA;
|
||||
$ivory: #FCFAF6,
|
||||
$white: #ffffff;
|
||||
$lightest-grey: #f5f5f5;
|
||||
$light-grey: #d3d3d3;
|
||||
$normal-grey: #c8c8c8;
|
||||
$black: #11243e;
|
||||
$primary: #6142d4;
|
||||
$secondary: #f3ecff;
|
||||
$tertiary: #f6f4ff;
|
||||
$accent: #13abba;
|
||||
$highlight: #fafafa;
|
||||
$ivory: #fcfaf6;
|
||||
$chat-bg-gray: #d9d9d9;
|
||||
|
Loading…
Reference in New Issue
Block a user