Minor Update to UI (#1692)

New sidebar / chatbar color, hidable right-panel, and many more small tweaks.

---------

Co-authored-by: pablodanswer <“pablo@danswer.ai”>
This commit is contained in:
pablodanswer 2024-06-26 13:54:41 -07:00 committed by GitHub
parent 20c4cdbdda
commit d6e5a98a22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 341 additions and 220 deletions

View File

@ -7,6 +7,7 @@ import { FiBookmark, FiCpu, FiInfo, FiX, FiZoomIn } from "react-icons/fi";
import { HoverPopup } from "@/components/HoverPopup";
import { Modal } from "@/components/Modal";
import { useState } from "react";
import { FaCaretDown, FaCaretRight } from "react-icons/fa";
import { Logo } from "@/components/Logo";
const MAX_PERSONAS_TO_DISPLAY = 4;
@ -37,6 +38,8 @@ export function ChatIntro({
}) {
const availableSourceMetadata = getSourceMetadataForSources(availableSources);
const [displaySources, setDisplaySources] = useState(false);
return (
<>
<div className="flex justify-center items-center h-full">
@ -90,12 +93,13 @@ export function ChatIntro({
</div>
</div>
)}
{availableSources.length > 0 && (
<div className="mt-2">
<div className="mt-1">
<p className="font-bold mb-1 mt-4 text-emphasis">
Connected Sources:{" "}
</p>
<div className="flex flex-wrap gap-2">
<div className={`flex flex-wrap gap-2`}>
{availableSourceMetadata.map((sourceMetadata) => (
<span
key={sourceMetadata.internalName}

View File

@ -45,7 +45,6 @@ import { useDocumentSelection } from "./useDocumentSelection";
import { useFilters, useLlmOverride } from "@/lib/hooks";
import { computeAvailableFilters } from "@/lib/filters";
import { FeedbackType } from "./types";
import ResizableSection from "@/components/resizable/ResizableSection";
import { DocumentSidebar } from "./documentSidebar/DocumentSidebar";
import { DanswerInitializingLoader } from "@/components/DanswerInitializingLoader";
import { FeedbackModal } from "./modal/FeedbackModal";
@ -74,6 +73,10 @@ import { v4 as uuidv4 } from "uuid";
import { orderAssistantsForUser } from "@/lib/assistants/orderAssistants";
import { ChatPopup } from "./ChatPopup";
import { ChatBanner } from "./ChatBanner";
import { TbLayoutSidebarRightExpand } from "react-icons/tb";
import { SIDEBAR_WIDTH_CONST } from "@/lib/constants";
import ResizableSection from "@/components/resizable/ResizableSection";
const MAX_INPUT_HEIGHT = 200;
const TEMP_USER_MESSAGE_ID = -1;
@ -256,6 +259,19 @@ export function ChatPage({
initialSessionFetch();
}, [existingChatSessionId]);
const [usedSidebarWidth, setUsedSidebarWidth] = useState<number>(
documentSidebarInitialWidth || parseInt(SIDEBAR_WIDTH_CONST)
);
const updateSidebarWidth = (newWidth: number) => {
setUsedSidebarWidth(newWidth);
if (sidebarElementRef.current && innerSidebarElementRef.current) {
sidebarElementRef.current.style.transition = "";
sidebarElementRef.current.style.width = `${newWidth}px`;
innerSidebarElementRef.current.style.width = `${newWidth}px`;
}
};
const [chatSessionId, setChatSessionId] = useState<number | null>(
existingChatSessionId
);
@ -472,6 +488,7 @@ export function ChatPage({
}
}
};
useEffect(() => {
adjustDocumentSidebarWidth(); // Adjust the width on initial render
window.addEventListener("resize", adjustDocumentSidebarWidth); // Add resize event listener
@ -865,12 +882,26 @@ export function ChatPage({
router.push("/search");
}
const [showDocSidebar, setShowDocSidebar] = useState(true); // State to track if sidebar is open
const toggleSidebar = () => {
if (sidebarElementRef.current) {
sidebarElementRef.current.style.transition = "width 0.3s ease-in-out";
sidebarElementRef.current.style.width = showDocSidebar
? "0px"
: `${usedSidebarWidth}px`;
}
setShowDocSidebar((showDocSidebar) => !showDocSidebar); // Toggle the state which will in turn toggle the class
};
const retrievalDisabled = !personaIncludesRetrieval(livePersona);
const sidebarElementRef = useRef<HTMLDivElement>(null);
const innerSidebarElementRef = useRef<HTMLDivElement>(null);
return (
<>
{/* <div className="absolute top-0 z-40 w-full">
<Header user={user} />
</div> */}
<HealthCheckBanner />
<InstantSSRAutoRefresh />
@ -886,7 +917,7 @@ export function ChatPage({
openedFolders={openedFolders}
/>
<div className="flex w-full overflow-x-hidden" ref={masterFlexboxRef}>
<div ref={masterFlexboxRef} className="flex w-full overflow-x-hidden">
{popup}
{currentFeedback && (
<FeedbackModal
@ -939,7 +970,10 @@ export function ChatPage({
<div
className={`w-full sm:relative h-screen ${
retrievalDisabled ? "pb-[111px]" : "pb-[140px]"
}`}
}
flex-auto transition-margin duration-300
overflow-x-auto
`}
{...getRootProps()}
>
{/* <input {...getInputProps()} /> */}
@ -963,7 +997,7 @@ export function ChatPage({
/>
</div>
<div className="ml-auto mr-8 flex">
<div className="ml-auto mr-6 flex">
{chatSessionId !== null && (
<div
onClick={() => setSharingModalVisible(true)}
@ -979,8 +1013,16 @@ export function ChatPage({
</div>
)}
<div className="ml-4 my-auto">
<div className="ml-4 flex my-auto">
<UserDropdown user={user} />
{!retrievalDisabled && !showDocSidebar && (
<button
className="ml-4 mt-auto"
onClick={() => toggleSidebar()}
>
<TbLayoutSidebarRightExpand size={24} />
</button>
)}
</div>
</div>
</div>
@ -1047,7 +1089,6 @@ export function ChatPage({
newCompleteMessageMap
);
setSelectedMessageForDocDisplay(messageId);
// set message as latest so we can edit this message
// and so it sticks around on page reload
setMessageAsLatest(messageId);
@ -1076,9 +1117,7 @@ export function ChatPage({
citedDocuments={getCitedDocumentsFromMessage(
message
)}
toolCall={
message.toolCalls && message.toolCalls[0]
}
toolCall={message?.toolCalls?.[0]}
isComplete={
i !== messageHistory.length - 1 ||
!isStreaming
@ -1273,21 +1312,31 @@ export function ChatPage({
</div>
{!retrievalDisabled ? (
<ResizableSection
intialWidth={documentSidebarInitialWidth as number}
minWidth={400}
maxWidth={maxDocumentSidebarWidth || undefined}
<div
ref={sidebarElementRef}
className={`relative flex-none overflow-y-hidden sidebar bg-background-weak h-screen`}
style={{ width: showDocSidebar ? usedSidebarWidth : 0 }}
>
<DocumentSidebar
selectedMessage={aiMessage}
selectedDocuments={selectedDocuments}
toggleDocumentSelection={toggleDocumentSelection}
clearSelectedDocuments={clearSelectedDocuments}
selectedDocumentTokens={selectedDocumentTokens}
maxTokens={maxTokens}
isLoading={isFetchingChatMessages}
/>
</ResizableSection>
<ResizableSection
updateSidebarWidth={updateSidebarWidth}
intialWidth={usedSidebarWidth}
minWidth={300}
maxWidth={maxDocumentSidebarWidth || undefined}
>
<DocumentSidebar
initialWidth={showDocSidebar ? usedSidebarWidth : 0}
ref={innerSidebarElementRef}
closeSidebar={() => toggleSidebar()}
selectedMessage={aiMessage}
selectedDocuments={selectedDocuments}
toggleDocumentSelection={toggleDocumentSelection}
clearSelectedDocuments={clearSelectedDocuments}
selectedDocumentTokens={selectedDocumentTokens}
maxTokens={maxTokens}
isLoading={isFetchingChatMessages}
/>
</ResizableSection>
</div>
) : // Another option is to use a div with the width set to the initial width, so that the
// chat section appears in the same place as before
// <div style={documentSidebarInitialWidth ? {width: documentSidebarInitialWidth} : {}}></div>

View File

@ -130,8 +130,8 @@ export function ChatPersonaSelector({
</div>
}
>
<div className="select-none text-xl text-strong font-bold flex px-2 py-1.5 rounded cursor-pointer hover:bg-hover-light">
<div className="my-auto">
<div className="select-none text-xl text-strong font-bold flex px-2 rounded cursor-pointer hover:bg-hover-light">
<div className="mt-auto">
{currentlySelectedPersona?.name || "Default"}
</div>
<FiChevronDown className="my-auto ml-1" />

View File

@ -7,33 +7,41 @@ import { SelectedDocumentDisplay } from "./SelectedDocumentDisplay";
import { removeDuplicateDocs } from "@/lib/documentUtils";
import { BasicSelectable } from "@/components/BasicClickable";
import { Message, RetrievalType } from "../interfaces";
import { SIDEBAR_WIDTH } from "@/lib/constants";
import { HoverPopup } from "@/components/HoverPopup";
import { HEADER_PADDING } from "@/lib/constants";
import { TbLayoutSidebarLeftExpand } from "react-icons/tb";
import { ForwardedRef, forwardRef } from "react";
function SectionHeader({
name,
icon,
closeHeader,
}: {
name: string;
icon: React.FC<{ className: string }>;
closeHeader?: () => void;
}) {
return (
<div className="text-lg text-emphasis font-medium flex pb-0.5 mb-3.5 mt-2 font-bold">
{icon({ className: "my-auto mr-1" })}
{name}
<div
className={`w-full mt-3 flex text-lg text-emphasis font-medium flex mb-3.5 font-bold flex items-end`}
>
<div className="flex mt-auto justify-between w-full">
<p className="flex">
{icon({ className: "my-auto mr-1" })}
{name}
</p>
{closeHeader && (
<button onClick={() => closeHeader()}>
<TbLayoutSidebarLeftExpand size={24} />
</button>
)}
</div>
</div>
);
}
export function DocumentSidebar({
selectedMessage,
selectedDocuments,
toggleDocumentSelection,
clearSelectedDocuments,
selectedDocumentTokens,
maxTokens,
isLoading,
}: {
interface DocumentSidebarProps {
closeSidebar: () => void;
selectedMessage: Message | null;
selectedDocuments: DanswerDocument[] | null;
toggleDocumentSelection: (document: DanswerDocument) => void;
@ -41,174 +49,203 @@ export function DocumentSidebar({
selectedDocumentTokens: number;
maxTokens: number;
isLoading: boolean;
}) {
const { popup, setPopup } = usePopup();
initialWidth: number;
}
const selectedMessageRetrievalType = selectedMessage?.retrievalType || null;
export const DocumentSidebar = forwardRef<HTMLDivElement, DocumentSidebarProps>(
(
{
closeSidebar,
selectedMessage,
selectedDocuments,
toggleDocumentSelection,
clearSelectedDocuments,
selectedDocumentTokens,
maxTokens,
isLoading,
initialWidth,
},
ref: ForwardedRef<HTMLDivElement>
) => {
const { popup, setPopup } = usePopup();
const selectedDocumentIds =
selectedDocuments?.map((document) => document.document_id) || [];
const selectedMessageRetrievalType = selectedMessage?.retrievalType || null;
const currentDocuments = selectedMessage?.documents || null;
const dedupedDocuments = removeDuplicateDocs(currentDocuments || []);
const selectedDocumentIds =
selectedDocuments?.map((document) => document.document_id) || [];
// NOTE: do not allow selection if less than 75 tokens are left
// this is to prevent the case where they are able to select the doc
// but it basically is unused since it's truncated right at the very
// start of the document (since title + metadata + misc overhead) takes up
// space
const tokenLimitReached = selectedDocumentTokens > maxTokens - 75;
return (
<div
className={`
flex-initial
overflow-y-hidden
flex
flex-col
w-full
h-screen
`}
id="document-sidebar"
>
{popup}
const currentDocuments = selectedMessage?.documents || null;
const dedupedDocuments = removeDuplicateDocs(currentDocuments || []);
<div className="h-4/6 flex flex-col mt-4">
<div className="px-3 mb-3 flex border-b border-border">
<SectionHeader
name={
selectedMessageRetrievalType === RetrievalType.SelectedDocs
? "Referenced Documents"
: "Retrieved Documents"
}
icon={FiFileText}
/>
</div>
// NOTE: do not allow selection if less than 75 tokens are left
// this is to prevent the case where they are able to select the doc
// but it basically is unused since it's truncated right at the very
// start of the document (since title + metadata + misc overhead) takes up
// space
const tokenLimitReached = selectedDocumentTokens > maxTokens - 75;
{currentDocuments ? (
<div className="overflow-y-auto dark-scrollbar flex flex-col">
<div>
{dedupedDocuments.length > 0 ? (
dedupedDocuments.map((document, ind) => (
<div
key={document.document_id}
className={
ind === dedupedDocuments.length - 1
? "mb-5"
: "border-b border-border-light mb-3"
}
>
<ChatDocumentDisplay
document={document}
setPopup={setPopup}
queryEventId={null}
isAIPick={false}
isSelected={selectedDocumentIds.includes(
document.document_id
)}
handleSelect={(documentId) => {
toggleDocumentSelection(
dedupedDocuments.find(
(document) => document.document_id === documentId
)!
);
}}
tokenLimitReached={tokenLimitReached}
/>
</div>
))
) : (
<div className="mx-3">
<Text>No documents found for the query.</Text>
</div>
)}
return (
<div
style={{ width: initialWidth }}
ref={ref}
className={`sidebar absolute right-0 h-screen border-l border-l-border`}
>
<div
className="w-full flex-initial
overflow-y-hidden
flex
flex-col h-screen"
>
{popup}
<div className="h-4/6 flex flex-col">
<div className="pl-3 pr-6 mb-3 flex border-b border-border">
<SectionHeader
name={
selectedMessageRetrievalType === RetrievalType.SelectedDocs
? "Referenced Documents"
: "Retrieved Documents"
}
icon={FiFileText}
closeHeader={closeSidebar}
/>
</div>
</div>
) : (
!isLoading && (
<div className="ml-4 mr-3">
<Text>
When you run ask a question, the retrieved documents will show
up here!
</Text>
</div>
)
)}
</div>
<div className="text-sm mb-4 border-t border-border pt-4 overflow-y-hidden flex flex-col">
<div className="flex border-b border-border px-3">
<div className="flex">
<SectionHeader name="Selected Documents" icon={FiFileText} />
{tokenLimitReached && (
<div className="ml-2 my-auto">
<div className="mb-2">
<HoverPopup
mainContent={
<FiAlertTriangle
className="text-alert my-auto"
size="16"
/>
}
popupContent={
<Text className="w-40">
Over LLM context length by:{" "}
<i>{selectedDocumentTokens - maxTokens} tokens</i>
<br />
<br />
{selectedDocuments && selectedDocuments.length > 0 && (
<>
Truncating: &quot;
<i>
{
selectedDocuments[selectedDocuments.length - 1]
.semantic_identifier
}
</i>
&quot;
</>
)}
</Text>
}
direction="left"
/>
{currentDocuments ? (
<div className="overflow-y-auto dark-scrollbar flex flex-col">
<div>
{dedupedDocuments.length > 0 ? (
dedupedDocuments.map((document, ind) => (
<div
key={document.document_id}
className={
ind === dedupedDocuments.length - 1
? "mb-5"
: "border-b border-border-light mb-3"
}
>
<ChatDocumentDisplay
document={document}
setPopup={setPopup}
queryEventId={null}
isAIPick={false}
isSelected={selectedDocumentIds.includes(
document.document_id
)}
handleSelect={(documentId) => {
toggleDocumentSelection(
dedupedDocuments.find(
(document) =>
document.document_id === documentId
)!
);
}}
tokenLimitReached={tokenLimitReached}
/>
</div>
))
) : (
<div className="mx-3">
<Text>No documents found for the query.</Text>
</div>
)}
</div>
</div>
) : (
!isLoading && (
<div className="ml-4 mr-3">
<Text>
When you run ask a question, the retrieved documents will
show up here!
</Text>
</div>
)
)}
</div>
{selectedDocuments && selectedDocuments.length > 0 && (
<div className="ml-auto my-auto" onClick={clearSelectedDocuments}>
<BasicSelectable selected={false}>De-Select All</BasicSelectable>
<div className="text-sm mb-4 border-t border-border pt-4 overflow-y-hidden flex flex-col">
<div className="flex border-b border-border px-3">
<div className="flex">
<SectionHeader name="Selected Documents" icon={FiFileText} />
{tokenLimitReached && (
<div className="ml-2 my-auto">
<div className="mb-2">
<HoverPopup
mainContent={
<FiAlertTriangle
className="text-alert my-auto"
size="16"
/>
}
popupContent={
<Text className="w-40">
Over LLM context length by:{" "}
<i>{selectedDocumentTokens - maxTokens} tokens</i>
<br />
<br />
{selectedDocuments &&
selectedDocuments.length > 0 && (
<>
Truncating: &quot;
<i>
{
selectedDocuments[
selectedDocuments.length - 1
].semantic_identifier
}
</i>
&quot;
</>
)}
</Text>
}
direction="left"
/>
</div>
</div>
)}
</div>
{selectedDocuments && selectedDocuments.length > 0 && (
<div
className="ml-auto my-auto"
onClick={clearSelectedDocuments}
>
<BasicSelectable selected={false}>
De-Select All
</BasicSelectable>
</div>
)}
</div>
)}
</div>
{selectedDocuments && selectedDocuments.length > 0 ? (
<div className="flex flex-col gap-y-2 py-3 px-3 overflow-y-auto dark-scrollbar max-h-full">
{selectedDocuments.map((document) => (
<SelectedDocumentDisplay
key={document.document_id}
document={document}
handleDeselect={(documentId) => {
toggleDocumentSelection(
dedupedDocuments.find(
(document) => document.document_id === documentId
)!
);
}}
/>
))}
{selectedDocuments && selectedDocuments.length > 0 ? (
<div className="flex flex-col gap-y-2 py-3 px-3 overflow-y-auto dark-scrollbar max-h-full">
{selectedDocuments.map((document) => (
<SelectedDocumentDisplay
key={document.document_id}
document={document}
handleDeselect={(documentId) => {
toggleDocumentSelection(
dedupedDocuments.find(
(document) => document.document_id === documentId
)!
);
}}
/>
))}
</div>
) : (
!isLoading && (
<Text className="mx-3 py-3">
Select documents from the retrieved documents section to chat
specifically with them!
</Text>
)
)}
</div>
) : (
!isLoading && (
<Text className="mx-3 py-3">
Select documents from the retrieved documents section to chat
specifically with them!
</Text>
)
)}
</div>
</div>
</div>
);
}
);
}
);
DocumentSidebar.displayName = "DocumentSidebar";

View File

@ -26,7 +26,7 @@ export function DocumentPreview({
flex
items-center
p-2
bg-hover-light
bg-hover
border
border-border
rounded-md

View File

@ -84,9 +84,10 @@ export function ChatInputBar({
flex
flex-col
border
border-border
border-border-medium
rounded-lg
bg-background
overflow-hidden
bg-background-weak
[&:has(textarea:focus)]::ring-1
[&:has(textarea:focus)]::ring-black
"
@ -118,13 +119,14 @@ export function ChatInputBar({
shrink
resize-none
border-0
bg-transparent
bg-background-weak
${
textAreaRef.current &&
textAreaRef.current.scrollHeight > MAX_INPUT_HEIGHT
? "overflow-y-auto mt-2"
: ""
}
overflow-hidden
whitespace-normal
break-word
overscroll-contain
@ -157,7 +159,7 @@ export function ChatInputBar({
}}
suppressContentEditableWarning={true}
/>
<div className="flex items-center space-x-3 px-4 pb-2">
<div className="flex items-center space-x-3 px-4 pb-2">
<ChatInputOption
name={selectedAssistant ? selectedAssistant.name : "Assistants"}
icon={FaBrain}

View File

@ -497,6 +497,7 @@ export const HumanMessage = ({
placeholder-gray-400
resize-none
pl-4
overflow-y-auto
pr-12
py-4`}
aria-multiline
@ -505,7 +506,6 @@ export const HumanMessage = ({
style={{ scrollbarWidth: "thin" }}
onChange={(e) => {
setEditedContent(e.target.value);
e.target.style.height = "auto";
e.target.style.height = `${e.target.scrollHeight}px`;
}}
onKeyDown={(e) => {
@ -514,6 +514,10 @@ export const HumanMessage = ({
setEditedContent(content);
setIsEditing(false);
}
// Submit edit if "Command Enter" is pressed, like in ChatGPT
if (e.key === "Enter" && e.metaKey) {
handleEditSubmit();
}
}}
// ref={(textarea) => {
// if (textarea) {

View File

@ -198,7 +198,7 @@ export function ChatSessionDisplay({
<div className="absolute bottom-0 right-0 top-0 bg-gradient-to-l to-transparent from-hover w-20 from-60% rounded" />
)}
{!isSelected && !delayedSkipGradient && (
<div className="absolute bottom-0 right-0 top-0 bg-gradient-to-l to-transparent from-background w-8 from-0% rounded" />
<div className="absolute bottom-0 right-0 top-0 bg-gradient-to-l to-transparent from-background-weak w-8 from-0% rounded" />
)}
</>
</BasicSelectable>

View File

@ -7,10 +7,12 @@ import Image from "next/image";
import { useRouter } from "next/navigation";
import { BasicClickable, BasicSelectable } from "@/components/BasicClickable";
import { ChatSession } from "../interfaces";
import {
NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA,
NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED,
NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA,
} from "@/lib/constants";
import { ChatTab } from "./ChatTab";
import { Folder } from "../folders/interfaces";
import { createFolder } from "../folders/FolderManagement";
@ -56,8 +58,10 @@ export const ChatSidebar = ({
{popup}
<div
className={`
flex-none
w-64
flex
flex-none
bg-background-weak
3xl:w-72
border-r
border-border

View File

@ -20,8 +20,9 @@ export function BasicClickable({
text-sm
p-1
h-full
bg-background
select-none
hover:bg-hover
hover:bg-hover-light
${fullWidth ? "w-full" : ""}`}
>
{children}
@ -65,11 +66,13 @@ export function BasicSelectable({
selected,
hasBorder,
fullWidth = false,
padding = true,
}: {
children: string | JSX.Element;
selected: boolean;
hasBorder?: boolean;
fullWidth?: boolean;
padding?: boolean;
}) {
return (
<div
@ -78,7 +81,7 @@ export function BasicSelectable({
font-medium
text-emphasis
text-sm
p-1
${padding && "p-1"}
select-none
${hasBorder ? "border border-border" : ""}
${selected ? "bg-hover" : "hover:bg-hover"}

View File

@ -49,12 +49,12 @@ export function UserDropdown({
open={userInfoVisible}
onOpenChange={setUserInfoVisible}
content={
<BasicSelectable selected={false}>
<BasicSelectable padding={false} selected={false}>
<div
onClick={() => setUserInfoVisible(!userInfoVisible)}
className="flex cursor-pointer"
>
<div className="my-auto bg-user rounded-lg px-2 text-base font-normal">
<div className="my-auto bg-user hover:bg-user-hover rounded-lg px-2 text-base font-normal">
{user && user.email ? user.email[0].toUpperCase() : "A"}
</div>
</div>

View File

@ -69,7 +69,7 @@ export async function Layout({ children }: { children: React.ReactNode }) {
<Header user={user} />
</div>
<div className="flex h-full pt-16">
<div className="w-80 pt-12 pb-8 h-full border-r border-border overflow-auto">
<div className="w-80 bg-background-weak pt-12 pb-8 h-full border-r border-border overflow-auto">
<AdminSidebar
collections={[
{

View File

@ -23,7 +23,7 @@ export function AdminSidebar({ collections }: { collections: Collection[] }) {
</h2>
{collection.items.map((item) => (
<Link key={item.link} href={item.link}>
<button className="text-sm block w-48 py-2 px-2 text-left hover:bg-hover-light rounded">
<button className="text-sm block w-48 py-2 px-2 text-left hover:bg-hover rounded">
<div className="">{item.name}</div>
</button>
</Link>

View File

@ -20,11 +20,13 @@ function applyMinAndMax(
}
export function ResizableSection({
updateSidebarWidth,
children,
intialWidth,
minWidth,
maxWidth,
}: {
updateSidebarWidth?: (newWidth: number) => void;
children: JSX.Element;
intialWidth: number;
minWidth: number;
@ -56,6 +58,9 @@ export function ResizableSection({
const delta = mouseMoveEvent.clientX - startX;
let newWidth = applyMinAndMax(width - delta, minWidth, maxWidth);
setWidth(newWidth);
if (updateSidebarWidth) {
updateSidebarWidth(newWidth);
}
Cookies.set(DOCUMENT_SIDEBAR_WIDTH_COOKIE_NAME, newWidth.toString(), {
path: "/",
});

View File

@ -1,6 +1,9 @@
export type AuthType = "disabled" | "basic" | "google_oauth" | "oidc" | "saml";
export const HOST_URL = process.env.WEB_DOMAIN || "http://127.0.0.1:3000";
export const HEADER_HEIGHT = "h-16";
export const SUB_HEADER = "h-12";
export const INTERNAL_URL = process.env.INTERNAL_URL || "http://127.0.0.1:8080";
export const NEXT_PUBLIC_DISABLE_STREAMING =
process.env.NEXT_PUBLIC_DISABLE_STREAMING?.toLowerCase() === "true";
@ -20,7 +23,8 @@ export const GOOGLE_DRIVE_AUTH_IS_ADMIN_COOKIE_NAME =
export const SEARCH_TYPE_COOKIE_NAME = "search_type";
export const HEADER_PADDING = `pt-[64px]`;
export const SIDEBAR_WIDTH_CONST = "350px";
export const SIDEBAR_WIDTH = `w-[350px]`;
export const LOGOUT_DISABLED =
process.env.NEXT_PUBLIC_DISABLE_LOGOUT?.toLowerCase() === "true";
@ -31,6 +35,12 @@ export const LOGOUT_DISABLED =
// it will not be accurate (will always be false).
export const SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED =
process.env.ENABLE_PAID_ENTERPRISE_EDITION_FEATURES?.toLowerCase() === "true";
// NOTE: since this is a `NEXT_PUBLIC_` variable, it will be set at
// build-time
// TODO: consider moving this to an API call so that the api_server
// can be the single source of truth
export const EE_ENABLED =
process.env.NEXT_PUBLIC_ENABLE_PAID_EE_FEATURES?.toLowerCase() === "true";
export const CUSTOM_ANALYTICS_ENABLED = process.env.CUSTOM_ANALYTICS_SECRET_KEY
? true

View File

@ -43,6 +43,8 @@ module.exports = {
"background-strong": "#eaecef",
"background-search": "#ffffff",
"background-custom-header": "#f3f4f6",
"background-inverted": "#000000",
"background-weak": "#f3f4f6", // gray-100
// text or icons
link: "#3b82f6", // blue-500
@ -60,6 +62,7 @@ module.exports = {
// borders
border: "#e5e7eb", // gray-200
"border-light": "#f3f4f6", // gray-100
"border-medium": "#d1d5db", // gray-300
"border-strong": "#9ca3af", // gray-400
// hover
@ -73,13 +76,6 @@ module.exports = {
text: "#fef9c3", // yellow-100
},
// bubbles in chat for each "user"
user: "#fb7185", // yellow-400
ai: "#60a5fa", // blue-400
// for display documents
document: "#ec4899", // pink-500
// scrollbar
scrollbar: {
track: "#f9fafb",
@ -92,6 +88,13 @@ module.exports = {
},
},
// bubbles in chat for each "user"
user: "#fb7185", // yellow-400
ai: "#60a5fa", // blue-400
// for display documents
document: "#ec4899", // pink-500
// light mode
tremor: {
brand: {