mirror of
				https://github.com/ItzCrazyKns/Perplexica.git
				synced 2025-11-04 04:38:15 +00:00 
			
		
		
		
	Added compact mode for more concise answers.
Made optimization mode persist between page refreshes. Added mode switcher to chat so it can be changed while researching.
This commit is contained in:
		@@ -16,9 +16,17 @@ const Chat = ({
 | 
			
		||||
  setFileIds,
 | 
			
		||||
  files,
 | 
			
		||||
  setFiles,
 | 
			
		||||
  isCompact,
 | 
			
		||||
  setIsCompact,
 | 
			
		||||
  optimizationMode,
 | 
			
		||||
  setOptimizationMode,
 | 
			
		||||
}: {
 | 
			
		||||
  messages: Message[];
 | 
			
		||||
  sendMessage: (message: string) => void;
 | 
			
		||||
  sendMessage: (
 | 
			
		||||
    message: string,
 | 
			
		||||
    messageId?: string,
 | 
			
		||||
    options?: { isCompact?: boolean },
 | 
			
		||||
  ) => void;
 | 
			
		||||
  loading: boolean;
 | 
			
		||||
  messageAppeared: boolean;
 | 
			
		||||
  rewrite: (messageId: string) => void;
 | 
			
		||||
@@ -26,6 +34,10 @@ const Chat = ({
 | 
			
		||||
  setFileIds: (fileIds: string[]) => void;
 | 
			
		||||
  files: File[];
 | 
			
		||||
  setFiles: (files: File[]) => void;
 | 
			
		||||
  isCompact: boolean;
 | 
			
		||||
  setIsCompact: (isCompact: boolean) => void;
 | 
			
		||||
  optimizationMode: string;
 | 
			
		||||
  setOptimizationMode: (mode: string) => void;
 | 
			
		||||
}) => {
 | 
			
		||||
  const [dividerWidth, setDividerWidth] = useState(0);
 | 
			
		||||
  const dividerRef = useRef<HTMLDivElement | null>(null);
 | 
			
		||||
@@ -71,6 +83,7 @@ const Chat = ({
 | 
			
		||||
              dividerRef={isLast ? dividerRef : undefined}
 | 
			
		||||
              isLast={isLast}
 | 
			
		||||
              rewrite={rewrite}
 | 
			
		||||
              isCompact={isCompact}
 | 
			
		||||
              sendMessage={sendMessage}
 | 
			
		||||
            />
 | 
			
		||||
            {!isLast && msg.role === 'assistant' && (
 | 
			
		||||
@@ -83,7 +96,7 @@ const Chat = ({
 | 
			
		||||
      <div ref={messageEnd} className="h-0" />
 | 
			
		||||
      {dividerWidth > 0 && (
 | 
			
		||||
        <div
 | 
			
		||||
          className="bottom-24 lg:bottom-10 fixed z-40"
 | 
			
		||||
          className="bottom-24 lg:bottom-10 fixed"
 | 
			
		||||
          style={{ width: dividerWidth }}
 | 
			
		||||
        >
 | 
			
		||||
          <MessageInput
 | 
			
		||||
@@ -93,6 +106,10 @@ const Chat = ({
 | 
			
		||||
            setFileIds={setFileIds}
 | 
			
		||||
            files={files}
 | 
			
		||||
            setFiles={setFiles}
 | 
			
		||||
            isCompact={isCompact}
 | 
			
		||||
            setIsCompact={setIsCompact}
 | 
			
		||||
            optimizationMode={optimizationMode}
 | 
			
		||||
            setOptimizationMode={setOptimizationMode}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      )}
 | 
			
		||||
 
 | 
			
		||||
@@ -399,6 +399,7 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
 | 
			
		||||
  const [focusMode, setFocusMode] = useState('webSearch');
 | 
			
		||||
  const [optimizationMode, setOptimizationMode] = useState('speed');
 | 
			
		||||
  const [isCompact, setIsCompact] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const [isMessagesLoaded, setIsMessagesLoaded] = useState(false);
 | 
			
		||||
 | 
			
		||||
@@ -406,6 +407,21 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
 | 
			
		||||
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const savedCompactMode = localStorage.getItem('compactMode');
 | 
			
		||||
    const savedOptimizationMode = localStorage.getItem('optimizationMode');
 | 
			
		||||
 | 
			
		||||
    if (savedCompactMode !== null) {
 | 
			
		||||
      setIsCompact(savedCompactMode === 'true');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (savedOptimizationMode !== null) {
 | 
			
		||||
      setOptimizationMode(savedOptimizationMode);
 | 
			
		||||
    } else {
 | 
			
		||||
      localStorage.setItem('optimizationMode', optimizationMode);
 | 
			
		||||
    }
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (
 | 
			
		||||
      chatId &&
 | 
			
		||||
@@ -456,7 +472,11 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
    }
 | 
			
		||||
  }, [isMessagesLoaded, isWSReady]);
 | 
			
		||||
 | 
			
		||||
  const sendMessage = async (message: string, messageId?: string) => {
 | 
			
		||||
  const sendMessage = async (
 | 
			
		||||
    message: string,
 | 
			
		||||
    messageId?: string,
 | 
			
		||||
    options?: { isCompact?: boolean },
 | 
			
		||||
  ) => {
 | 
			
		||||
    if (loading) return;
 | 
			
		||||
    if (!ws || ws.readyState !== WebSocket.OPEN) {
 | 
			
		||||
      toast.error('Cannot send message while disconnected');
 | 
			
		||||
@@ -471,21 +491,21 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
    let added = false;
 | 
			
		||||
 | 
			
		||||
    messageId = messageId ?? crypto.randomBytes(7).toString('hex');
 | 
			
		||||
 | 
			
		||||
    ws.send(
 | 
			
		||||
      JSON.stringify({
 | 
			
		||||
        type: 'message',
 | 
			
		||||
        message: {
 | 
			
		||||
          messageId: messageId,
 | 
			
		||||
          chatId: chatId!,
 | 
			
		||||
          content: message,
 | 
			
		||||
        },
 | 
			
		||||
        files: fileIds,
 | 
			
		||||
        focusMode: focusMode,
 | 
			
		||||
        optimizationMode: optimizationMode,
 | 
			
		||||
        history: [...chatHistory, ['human', message]],
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    let messageData = {
 | 
			
		||||
      type: 'message',
 | 
			
		||||
      message: {
 | 
			
		||||
        messageId: messageId,
 | 
			
		||||
        chatId: chatId!,
 | 
			
		||||
        content: message,
 | 
			
		||||
      },
 | 
			
		||||
      files: fileIds,
 | 
			
		||||
      focusMode: focusMode,
 | 
			
		||||
      optimizationMode: optimizationMode,
 | 
			
		||||
      history: [...chatHistory, ['human', message]],
 | 
			
		||||
      isCompact: options?.isCompact ?? isCompact,
 | 
			
		||||
    };
 | 
			
		||||
    //console.log('sending:', messageData, JSON.stringify(messageData));
 | 
			
		||||
    ws.send(JSON.stringify(messageData));
 | 
			
		||||
 | 
			
		||||
    setMessages((prevMessages) => [
 | 
			
		||||
      ...prevMessages,
 | 
			
		||||
@@ -615,12 +635,12 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
      return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    sendMessage(message.content, message.messageId);
 | 
			
		||||
    sendMessage(message.content, message.messageId, { isCompact });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (isReady && initialMessage && ws?.readyState === 1) {
 | 
			
		||||
      sendMessage(initialMessage);
 | 
			
		||||
      sendMessage(initialMessage, undefined, { isCompact });
 | 
			
		||||
    }
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [ws?.readyState, isReady, initialMessage, isWSReady]);
 | 
			
		||||
@@ -660,6 +680,10 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
              setFileIds={setFileIds}
 | 
			
		||||
              files={files}
 | 
			
		||||
              setFiles={setFiles}
 | 
			
		||||
              isCompact={isCompact}
 | 
			
		||||
              setIsCompact={setIsCompact}
 | 
			
		||||
              optimizationMode={optimizationMode}
 | 
			
		||||
              setOptimizationMode={setOptimizationMode}
 | 
			
		||||
            />
 | 
			
		||||
          </>
 | 
			
		||||
        ) : (
 | 
			
		||||
@@ -673,6 +697,8 @@ const ChatWindow = ({ id }: { id?: string }) => {
 | 
			
		||||
            setFileIds={setFileIds}
 | 
			
		||||
            files={files}
 | 
			
		||||
            setFiles={setFiles}
 | 
			
		||||
            isCompact={isCompact}
 | 
			
		||||
            setIsCompact={setIsCompact}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ const EmptyChat = ({
 | 
			
		||||
  setFileIds,
 | 
			
		||||
  files,
 | 
			
		||||
  setFiles,
 | 
			
		||||
  isCompact,
 | 
			
		||||
  setIsCompact,
 | 
			
		||||
}: {
 | 
			
		||||
  sendMessage: (message: string) => void;
 | 
			
		||||
  focusMode: string;
 | 
			
		||||
@@ -24,6 +26,8 @@ const EmptyChat = ({
 | 
			
		||||
  setFileIds: (fileIds: string[]) => void;
 | 
			
		||||
  files: File[];
 | 
			
		||||
  setFiles: (files: File[]) => void;
 | 
			
		||||
  isCompact: boolean;
 | 
			
		||||
  setIsCompact: (isCompact: boolean) => void;
 | 
			
		||||
}) => {
 | 
			
		||||
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
 | 
			
		||||
 | 
			
		||||
@@ -48,6 +52,8 @@ const EmptyChat = ({
 | 
			
		||||
          setFileIds={setFileIds}
 | 
			
		||||
          files={files}
 | 
			
		||||
          setFiles={setFiles}
 | 
			
		||||
          isCompact={isCompact}
 | 
			
		||||
          setIsCompact={setIsCompact}
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,14 @@ const EmptyChatMessageInput = ({
 | 
			
		||||
  setFileIds,
 | 
			
		||||
  files,
 | 
			
		||||
  setFiles,
 | 
			
		||||
  isCompact,
 | 
			
		||||
  setIsCompact,
 | 
			
		||||
}: {
 | 
			
		||||
  sendMessage: (message: string) => void;
 | 
			
		||||
  sendMessage: (
 | 
			
		||||
    message: string,
 | 
			
		||||
    messageId?: string,
 | 
			
		||||
    options?: { isCompact?: boolean },
 | 
			
		||||
  ) => void;
 | 
			
		||||
  focusMode: string;
 | 
			
		||||
  setFocusMode: (mode: string) => void;
 | 
			
		||||
  optimizationMode: string;
 | 
			
		||||
@@ -27,6 +33,8 @@ const EmptyChatMessageInput = ({
 | 
			
		||||
  setFileIds: (fileIds: string[]) => void;
 | 
			
		||||
  files: File[];
 | 
			
		||||
  setFiles: (files: File[]) => void;
 | 
			
		||||
  isCompact: boolean;
 | 
			
		||||
  setIsCompact: (isCompact: boolean) => void;
 | 
			
		||||
}) => {
 | 
			
		||||
  const [copilotEnabled, setCopilotEnabled] = useState(false);
 | 
			
		||||
  const [message, setMessage] = useState('');
 | 
			
		||||
@@ -61,13 +69,13 @@ const EmptyChatMessageInput = ({
 | 
			
		||||
    <form
 | 
			
		||||
      onSubmit={(e) => {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        sendMessage(message);
 | 
			
		||||
        sendMessage(message, undefined, { isCompact });
 | 
			
		||||
        setMessage('');
 | 
			
		||||
      }}
 | 
			
		||||
      onKeyDown={(e) => {
 | 
			
		||||
        if (e.key === 'Enter' && !e.shiftKey) {
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          sendMessage(message);
 | 
			
		||||
          sendMessage(message, undefined, { isCompact });
 | 
			
		||||
          setMessage('');
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
@@ -97,6 +105,8 @@ const EmptyChatMessageInput = ({
 | 
			
		||||
            <Optimization
 | 
			
		||||
              optimizationMode={optimizationMode}
 | 
			
		||||
              setOptimizationMode={setOptimizationMode}
 | 
			
		||||
              isCompact={isCompact}
 | 
			
		||||
              setIsCompact={setIsCompact}
 | 
			
		||||
            />
 | 
			
		||||
            <button
 | 
			
		||||
              disabled={message.trim().length === 0}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ const MessageBox = ({
 | 
			
		||||
  dividerRef,
 | 
			
		||||
  isLast,
 | 
			
		||||
  rewrite,
 | 
			
		||||
  isCompact,
 | 
			
		||||
  sendMessage,
 | 
			
		||||
}: {
 | 
			
		||||
  message: Message;
 | 
			
		||||
@@ -37,7 +38,12 @@ const MessageBox = ({
 | 
			
		||||
  dividerRef?: MutableRefObject<HTMLDivElement | null>;
 | 
			
		||||
  isLast: boolean;
 | 
			
		||||
  rewrite: (messageId: string) => void;
 | 
			
		||||
  sendMessage: (message: string) => void;
 | 
			
		||||
  isCompact: boolean;
 | 
			
		||||
  sendMessage: (
 | 
			
		||||
    message: string,
 | 
			
		||||
    messageId?: string,
 | 
			
		||||
    options?: { isCompact?: boolean },
 | 
			
		||||
  ) => void;
 | 
			
		||||
}) => {
 | 
			
		||||
  const [parsedMessage, setParsedMessage] = useState(message.content);
 | 
			
		||||
  const [speechMessage, setSpeechMessage] = useState(message.content);
 | 
			
		||||
@@ -65,6 +71,10 @@ const MessageBox = ({
 | 
			
		||||
 | 
			
		||||
  const { speechStatus, start, stop } = useSpeech({ text: speechMessage });
 | 
			
		||||
 | 
			
		||||
  const handleSuggestionClick = (suggestion: string) => {
 | 
			
		||||
    sendMessage(suggestion, undefined, { isCompact });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      {message.role === 'user' && (
 | 
			
		||||
@@ -163,7 +173,7 @@ const MessageBox = ({
 | 
			
		||||
                            <div className="h-px w-full bg-light-secondary dark:bg-dark-secondary" />
 | 
			
		||||
                            <div
 | 
			
		||||
                              onClick={() => {
 | 
			
		||||
                                sendMessage(suggestion);
 | 
			
		||||
                                handleSuggestionClick(suggestion);
 | 
			
		||||
                              }}
 | 
			
		||||
                              className="cursor-pointer flex flex-row justify-between font-medium space-x-2 items-center"
 | 
			
		||||
                            >
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from 'react';
 | 
			
		||||
import TextareaAutosize from 'react-textarea-autosize';
 | 
			
		||||
import Attach from './MessageInputActions/Attach';
 | 
			
		||||
import CopilotToggle from './MessageInputActions/Copilot';
 | 
			
		||||
import Optimization from './MessageInputActions/Optimization';
 | 
			
		||||
import { File } from './ChatWindow';
 | 
			
		||||
import AttachSmall from './MessageInputActions/AttachSmall';
 | 
			
		||||
 | 
			
		||||
@@ -14,13 +15,25 @@ const MessageInput = ({
 | 
			
		||||
  setFileIds,
 | 
			
		||||
  files,
 | 
			
		||||
  setFiles,
 | 
			
		||||
  isCompact,
 | 
			
		||||
  setIsCompact,
 | 
			
		||||
  optimizationMode,
 | 
			
		||||
  setOptimizationMode,
 | 
			
		||||
}: {
 | 
			
		||||
  sendMessage: (message: string) => void;
 | 
			
		||||
  sendMessage: (
 | 
			
		||||
    message: string,
 | 
			
		||||
    messageId?: string,
 | 
			
		||||
    options?: { isCompact?: boolean },
 | 
			
		||||
  ) => void;
 | 
			
		||||
  loading: boolean;
 | 
			
		||||
  fileIds: string[];
 | 
			
		||||
  setFileIds: (fileIds: string[]) => void;
 | 
			
		||||
  files: File[];
 | 
			
		||||
  setFiles: (files: File[]) => void;
 | 
			
		||||
  isCompact: boolean;
 | 
			
		||||
  setIsCompact: (isCompact: boolean) => void;
 | 
			
		||||
  optimizationMode: string;
 | 
			
		||||
  setOptimizationMode: (mode: string) => void;
 | 
			
		||||
}) => {
 | 
			
		||||
  const [copilotEnabled, setCopilotEnabled] = useState(false);
 | 
			
		||||
  const [message, setMessage] = useState('');
 | 
			
		||||
@@ -40,20 +53,16 @@ const MessageInput = ({
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleKeyDown = (e: KeyboardEvent) => {
 | 
			
		||||
      const activeElement = document.activeElement;
 | 
			
		||||
 | 
			
		||||
      const isInputFocused =
 | 
			
		||||
        activeElement?.tagName === 'INPUT' ||
 | 
			
		||||
        activeElement?.tagName === 'TEXTAREA' ||
 | 
			
		||||
        activeElement?.hasAttribute('contenteditable');
 | 
			
		||||
 | 
			
		||||
      if (e.key === '/' && !isInputFocused) {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        inputRef.current?.focus();
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    document.addEventListener('keydown', handleKeyDown);
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      document.removeEventListener('keydown', handleKeyDown);
 | 
			
		||||
    };
 | 
			
		||||
@@ -64,28 +73,36 @@ const MessageInput = ({
 | 
			
		||||
      onSubmit={(e) => {
 | 
			
		||||
        if (loading) return;
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        sendMessage(message);
 | 
			
		||||
        sendMessage(message, undefined, { isCompact });
 | 
			
		||||
        setMessage('');
 | 
			
		||||
      }}
 | 
			
		||||
      onKeyDown={(e) => {
 | 
			
		||||
        if (e.key === 'Enter' && !e.shiftKey && !loading) {
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          sendMessage(message);
 | 
			
		||||
          sendMessage(message, undefined, { isCompact });
 | 
			
		||||
          setMessage('');
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      className={cn(
 | 
			
		||||
        'bg-light-secondary dark:bg-dark-secondary p-4 flex items-center overflow-hidden border border-light-200 dark:border-dark-200',
 | 
			
		||||
        'bg-light-secondary dark:bg-dark-secondary p-4 flex items-center border border-light-200 dark:border-dark-200',
 | 
			
		||||
        mode === 'multi' ? 'flex-col rounded-lg' : 'flex-row rounded-full',
 | 
			
		||||
      )}
 | 
			
		||||
    >
 | 
			
		||||
      {mode === 'single' && (
 | 
			
		||||
        <AttachSmall
 | 
			
		||||
          fileIds={fileIds}
 | 
			
		||||
          setFileIds={setFileIds}
 | 
			
		||||
          files={files}
 | 
			
		||||
          setFiles={setFiles}
 | 
			
		||||
        />
 | 
			
		||||
        <div className="flex flex-row items-center space-x-2">
 | 
			
		||||
          <AttachSmall
 | 
			
		||||
            fileIds={fileIds}
 | 
			
		||||
            setFileIds={setFileIds}
 | 
			
		||||
            files={files}
 | 
			
		||||
            setFiles={setFiles}
 | 
			
		||||
          />
 | 
			
		||||
          <Optimization
 | 
			
		||||
            optimizationMode={optimizationMode}
 | 
			
		||||
            setOptimizationMode={setOptimizationMode}
 | 
			
		||||
            isCompact={isCompact}
 | 
			
		||||
            setIsCompact={setIsCompact}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      )}
 | 
			
		||||
      <TextareaAutosize
 | 
			
		||||
        ref={inputRef}
 | 
			
		||||
@@ -113,12 +130,20 @@ const MessageInput = ({
 | 
			
		||||
      )}
 | 
			
		||||
      {mode === 'multi' && (
 | 
			
		||||
        <div className="flex flex-row items-center justify-between w-full pt-2">
 | 
			
		||||
          <AttachSmall
 | 
			
		||||
            fileIds={fileIds}
 | 
			
		||||
            setFileIds={setFileIds}
 | 
			
		||||
            files={files}
 | 
			
		||||
            setFiles={setFiles}
 | 
			
		||||
          />
 | 
			
		||||
          <div className="flex flex-row items-center space-x-2">
 | 
			
		||||
            <AttachSmall
 | 
			
		||||
              fileIds={fileIds}
 | 
			
		||||
              setFileIds={setFileIds}
 | 
			
		||||
              files={files}
 | 
			
		||||
              setFiles={setFiles}
 | 
			
		||||
            />
 | 
			
		||||
            <Optimization
 | 
			
		||||
              optimizationMode={optimizationMode}
 | 
			
		||||
              setOptimizationMode={setOptimizationMode}
 | 
			
		||||
              isCompact={isCompact}
 | 
			
		||||
              setIsCompact={setIsCompact}
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
          <div className="flex flex-row items-center space-x-4">
 | 
			
		||||
            <CopilotToggle
 | 
			
		||||
              copilotEnabled={copilotEnabled}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { ChevronDown, Sliders, Star, Zap } from 'lucide-react';
 | 
			
		||||
import { ChevronDown, Minimize2, Sliders, Star, Zap } from 'lucide-react';
 | 
			
		||||
import { cn } from '@/lib/utils';
 | 
			
		||||
import {
 | 
			
		||||
  Popover,
 | 
			
		||||
@@ -6,8 +6,7 @@ import {
 | 
			
		||||
  PopoverPanel,
 | 
			
		||||
  Transition,
 | 
			
		||||
} from '@headlessui/react';
 | 
			
		||||
import { Fragment } from 'react';
 | 
			
		||||
 | 
			
		||||
import { Fragment, useEffect } from 'react';
 | 
			
		||||
const OptimizationModes = [
 | 
			
		||||
  {
 | 
			
		||||
    key: 'speed',
 | 
			
		||||
@@ -37,10 +36,33 @@ const OptimizationModes = [
 | 
			
		||||
const Optimization = ({
 | 
			
		||||
  optimizationMode,
 | 
			
		||||
  setOptimizationMode,
 | 
			
		||||
  isCompact,
 | 
			
		||||
  setIsCompact,
 | 
			
		||||
}: {
 | 
			
		||||
  optimizationMode: string;
 | 
			
		||||
  setOptimizationMode: (mode: string) => void;
 | 
			
		||||
  isCompact: boolean;
 | 
			
		||||
  setIsCompact: (isCompact: boolean) => void;
 | 
			
		||||
}) => {
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const savedCompactMode = localStorage.getItem('compactMode');
 | 
			
		||||
    if (savedCompactMode === null) {
 | 
			
		||||
      localStorage.setItem('compactMode', String(isCompact));
 | 
			
		||||
    } else {
 | 
			
		||||
      setIsCompact(savedCompactMode === 'true');
 | 
			
		||||
    }
 | 
			
		||||
  }, [setIsCompact]);
 | 
			
		||||
 | 
			
		||||
  const handleCompactChange = (checked: boolean) => {
 | 
			
		||||
    setIsCompact(checked);
 | 
			
		||||
    localStorage.setItem('compactMode', String(checked));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleOptimizationChange = (mode: string) => {
 | 
			
		||||
    setOptimizationMode(mode);
 | 
			
		||||
    localStorage.setItem('optimizationMode', mode);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg">
 | 
			
		||||
      <PopoverButton
 | 
			
		||||
@@ -70,11 +92,11 @@ const Optimization = ({
 | 
			
		||||
        leaveFrom="opacity-100 translate-y-0"
 | 
			
		||||
        leaveTo="opacity-0 translate-y-1"
 | 
			
		||||
      >
 | 
			
		||||
        <PopoverPanel className="absolute z-10 w-64 md:w-[250px] right-0">
 | 
			
		||||
        <PopoverPanel className="absolute z-10 w-64 md:w-[250px] right-0 bottom-[100%] mb-2">
 | 
			
		||||
          <div className="flex flex-col gap-2 bg-light-primary dark:bg-dark-primary border rounded-lg border-light-200 dark:border-dark-200 w-full p-4 max-h-[200px] md:max-h-none overflow-y-auto">
 | 
			
		||||
            {OptimizationModes.map((mode, i) => (
 | 
			
		||||
              <PopoverButton
 | 
			
		||||
                onClick={() => setOptimizationMode(mode.key)}
 | 
			
		||||
                onClick={() => handleOptimizationChange(mode.key)}
 | 
			
		||||
                key={i}
 | 
			
		||||
                disabled={mode.key === 'quality'}
 | 
			
		||||
                className={cn(
 | 
			
		||||
@@ -94,6 +116,30 @@ const Optimization = ({
 | 
			
		||||
                </p>
 | 
			
		||||
              </PopoverButton>
 | 
			
		||||
            ))}
 | 
			
		||||
            <div className="border-t border-light-200 dark:border-dark-200 pt-2 mt-1">
 | 
			
		||||
              <label className="flex items-center space-x-2 p-2 rounded-lg cursor-pointer hover:bg-light-secondary dark:hover:bg-dark-secondary">
 | 
			
		||||
                <input
 | 
			
		||||
                  type="checkbox"
 | 
			
		||||
                  checked={isCompact}
 | 
			
		||||
                  onChange={(e) => handleCompactChange(e.target.checked)}
 | 
			
		||||
                  className="form-checkbox h-4 w-4 text-blue-600 transition duration-150 ease-in-out"
 | 
			
		||||
                />
 | 
			
		||||
                <div className="flex items-center space-x-2">
 | 
			
		||||
                  <Minimize2
 | 
			
		||||
                    size={16}
 | 
			
		||||
                    className="text-gray-600 dark:text-gray-400"
 | 
			
		||||
                  />
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <p className="text-sm font-medium text-black dark:text-white">
 | 
			
		||||
                      Compact Mode
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p className="text-xs text-black/70 dark:text-white/70">
 | 
			
		||||
                      Generate more concise responses
 | 
			
		||||
                    </p>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </label>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </PopoverPanel>
 | 
			
		||||
      </Transition>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user