make all chat area components tabbable (accessibility) (#246)
* make all chat area components tabbable * align message role description * remove inline styles on icons * remove inline styles on icons
This commit is contained in:
		
							parent
							
								
									5d31947ab9
								
							
						
					
					
						commit
						a78a8c4a94
					
				|  | @ -217,16 +217,17 @@ export const Chat: FC<Props> = memo( | ||||||
|                 <> |                 <> | ||||||
|                   <div className="flex justify-center border border-b-neutral-300 bg-neutral-100 py-2 text-sm text-neutral-500 dark:border-none dark:bg-[#444654] dark:text-neutral-200"> |                   <div className="flex justify-center border border-b-neutral-300 bg-neutral-100 py-2 text-sm text-neutral-500 dark:border-none dark:bg-[#444654] dark:text-neutral-200"> | ||||||
|                     {t('Model')}: {conversation.model.name} |                     {t('Model')}: {conversation.model.name} | ||||||
|                     <IconSettings |                     <button | ||||||
|                       className="ml-2 cursor-pointer hover:opacity-50" |                       className="ml-2 cursor-pointer hover:opacity-50" | ||||||
|                       onClick={handleSettings} |                       onClick={handleSettings} | ||||||
|                       size={18} |                     > | ||||||
|                     /> |                     <IconSettings size={18} /> | ||||||
|                     <IconClearAll |                     </button> | ||||||
|  |                     <button | ||||||
|                       className="ml-2 cursor-pointer hover:opacity-50" |                       className="ml-2 cursor-pointer hover:opacity-50" | ||||||
|                       onClick={onClearAll} |                       onClick={onClearAll}> | ||||||
|                       size={18} |                     <IconClearAll size={18} /> | ||||||
|                     /> |                     </button> | ||||||
|                   </div> |                   </div> | ||||||
|                   {showSettings && ( |                   {showSettings && ( | ||||||
|                     <div className="flex flex-col space-y-10 md:mx-auto md:max-w-xl md:gap-6 md:py-3 md:pt-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl"> |                     <div className="flex flex-col space-y-10 md:mx-auto md:max-w-xl md:gap-6 md:py-3 md:pt-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl"> | ||||||
|  |  | ||||||
|  | @ -237,28 +237,26 @@ export const ChatInput: FC<Props> = ({ | ||||||
|       <div className="stretch mx-2 mt-4 flex flex-row gap-3 last:mb-2 md:mx-4 md:mt-[52px] md:last:mb-6 lg:mx-auto lg:max-w-3xl"> |       <div className="stretch mx-2 mt-4 flex flex-row gap-3 last:mb-2 md:mx-4 md:mt-[52px] md:last:mb-6 lg:mx-auto lg:max-w-3xl"> | ||||||
|         {messageIsStreaming && ( |         {messageIsStreaming && ( | ||||||
|           <button |           <button | ||||||
|             className="absolute top-2 left-0 right-0 mx-auto mt-2 w-fit rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:top-0" |             className="absolute left-0 right-0 mx-auto mt-2 flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:top-0" | ||||||
|             onClick={handleStopConversation} |             onClick={handleStopConversation} | ||||||
|           > |           > | ||||||
|             <IconPlayerStop size={16} className="mb-[2px] inline-block" />{' '} |             <IconPlayerStop size={16} /> {t('Stop Generating')} | ||||||
|             {t('Stop Generating')} |  | ||||||
|           </button> |           </button> | ||||||
|         )} |         )} | ||||||
| 
 | 
 | ||||||
|         {!messageIsStreaming && !conversationIsEmpty && ( |         {!messageIsStreaming && !conversationIsEmpty && ( | ||||||
|           <button |           <button | ||||||
|             className="absolute left-0 right-0 mx-auto mt-2 w-fit rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:top-0" |             className="absolute left-0 right-0 mx-auto mt-2 flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:top-0" | ||||||
|             onClick={onRegenerate} |             onClick={onRegenerate} | ||||||
|           > |           > | ||||||
|             <IconRepeat size={16} className="mb-[2px] inline-block" />{' '} |             <IconRepeat size={16} /> {t('Regenerate response')} | ||||||
|             {t('Regenerate response')} |  | ||||||
|           </button> |           </button> | ||||||
|         )} |         )} | ||||||
| 
 | 
 | ||||||
|         <div className="relative mx-2 flex w-full flex-grow flex-col rounded-md border border-black/10 bg-white py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 dark:bg-[#40414F] dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] sm:mx-4 md:py-3 md:pl-4"> |         <div className="relative mx-2 flex w-full flex-grow flex-col rounded-md border border-black/10 bg-white shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 dark:bg-[#40414F] dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] sm:mx-4"> | ||||||
|           <textarea |           <textarea | ||||||
|             ref={textareaRef} |             ref={textareaRef} | ||||||
|             className="m-0 w-full resize-none border-0 bg-transparent p-0 pr-8 pl-2 text-black outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:text-white md:pl-0" |             className="m-0 w-full resize-none border-0 bg-transparent p-0 pr-8 pl-2 text-black dark:bg-transparent dark:text-white py-2 md:py-3 md:pl-4" | ||||||
|             style={{ |             style={{ | ||||||
|               resize: 'none', |               resize: 'none', | ||||||
|               bottom: `${textareaRef?.current?.scrollHeight}px`, |               bottom: `${textareaRef?.current?.scrollHeight}px`, | ||||||
|  | @ -279,12 +277,11 @@ export const ChatInput: FC<Props> = ({ | ||||||
|             onChange={handleChange} |             onChange={handleChange} | ||||||
|             onKeyDown={handleKeyDown} |             onKeyDown={handleKeyDown} | ||||||
|           /> |           /> | ||||||
| 
 |  | ||||||
|           <button |           <button | ||||||
|             className="absolute right-3 rounded-sm p-1 text-neutral-800 hover:bg-neutral-200 hover:text-neutral-900 focus:outline-none dark:bg-opacity-50 dark:text-neutral-100 dark:hover:text-neutral-200" |             className="absolute right-2 top-2 rounded-sm p-1 text-neutral-800 hover:bg-neutral-200 hover:text-neutral-900 dark:bg-opacity-50 dark:text-neutral-100 dark:hover:text-neutral-200 opacity-60" | ||||||
|             onClick={handleSend} |             onClick={handleSend} | ||||||
|           > |           > | ||||||
|             <IconSend size={16} className="opacity-60" /> |             <IconSend size={18} /> | ||||||
|           </button> |           </button> | ||||||
| 
 | 
 | ||||||
|           {showPromptList && prompts.length > 0 && ( |           {showPromptList && prompts.length > 0 && ( | ||||||
|  |  | ||||||
|  | @ -2,12 +2,12 @@ import { Message } from '@/types/chat'; | ||||||
| import { IconEdit } from '@tabler/icons-react'; | import { IconEdit } from '@tabler/icons-react'; | ||||||
| import { useTranslation } from 'next-i18next'; | import { useTranslation } from 'next-i18next'; | ||||||
| import { FC, memo, useEffect, useRef, useState } from 'react'; | import { FC, memo, useEffect, useRef, useState } from 'react'; | ||||||
|  | import { IconCheck, IconCopy } from '@tabler/icons-react'; | ||||||
| import rehypeMathjax from 'rehype-mathjax'; | import rehypeMathjax from 'rehype-mathjax'; | ||||||
| import remarkGfm from 'remark-gfm'; | import remarkGfm from 'remark-gfm'; | ||||||
| import remarkMath from 'remark-math'; | import remarkMath from 'remark-math'; | ||||||
| import { CodeBlock } from '../Markdown/CodeBlock'; | import { CodeBlock } from '../Markdown/CodeBlock'; | ||||||
| import { MemoizedReactMarkdown } from '../Markdown/MemoizedReactMarkdown'; | import { MemoizedReactMarkdown } from '../Markdown/MemoizedReactMarkdown'; | ||||||
| import { CopyButton } from './CopyButton'; |  | ||||||
| 
 | 
 | ||||||
| interface Props { | interface Props { | ||||||
|   message: Message; |   message: Message; | ||||||
|  | @ -19,7 +19,6 @@ export const ChatMessage: FC<Props> = memo( | ||||||
|   ({ message, messageIndex, onEditMessage }) => { |   ({ message, messageIndex, onEditMessage }) => { | ||||||
|     const { t } = useTranslation('chat'); |     const { t } = useTranslation('chat'); | ||||||
|     const [isEditing, setIsEditing] = useState<boolean>(false); |     const [isEditing, setIsEditing] = useState<boolean>(false); | ||||||
|     const [isHovering, setIsHovering] = useState<boolean>(false); |  | ||||||
|     const [messageContent, setMessageContent] = useState(message.content); |     const [messageContent, setMessageContent] = useState(message.content); | ||||||
|     const [messagedCopied, setMessageCopied] = useState(false); |     const [messagedCopied, setMessageCopied] = useState(false); | ||||||
| 
 | 
 | ||||||
|  | @ -79,11 +78,9 @@ export const ChatMessage: FC<Props> = memo( | ||||||
|             : 'border-b border-black/10 bg-white text-gray-800 dark:border-gray-900/50 dark:bg-[#343541] dark:text-gray-100' |             : 'border-b border-black/10 bg-white text-gray-800 dark:border-gray-900/50 dark:bg-[#343541] dark:text-gray-100' | ||||||
|         }`}
 |         }`}
 | ||||||
|         style={{ overflowWrap: 'anywhere' }} |         style={{ overflowWrap: 'anywhere' }} | ||||||
|         onMouseEnter={() => setIsHovering(true)} |  | ||||||
|         onMouseLeave={() => setIsHovering(false)} |  | ||||||
|       > |       > | ||||||
|         <div className="relative m-auto flex gap-4 p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl"> |         <div className="relative m-auto flex gap-4 p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl"> | ||||||
|           <div className="min-w-[40px] font-bold"> |           <div className="min-w-[40px] font-bold text-right"> | ||||||
|             {message.role === 'assistant' ? t('AI') : t('You')}: |             {message.role === 'assistant' ? t('AI') : t('You')}: | ||||||
|           </div> |           </div> | ||||||
| 
 | 
 | ||||||
|  | @ -94,7 +91,7 @@ export const ChatMessage: FC<Props> = memo( | ||||||
|                   <div className="flex w-full flex-col"> |                   <div className="flex w-full flex-col"> | ||||||
|                     <textarea |                     <textarea | ||||||
|                       ref={textareaRef} |                       ref={textareaRef} | ||||||
|                       className="w-full resize-none whitespace-pre-wrap border-none outline-none dark:bg-[#343541]" |                       className="w-full resize-none whitespace-pre-wrap border-none dark:bg-[#343541]" | ||||||
|                       value={messageContent} |                       value={messageContent} | ||||||
|                       onChange={handleInputChange} |                       onChange={handleInputChange} | ||||||
|                       onKeyDown={handlePressEnter} |                       onKeyDown={handlePressEnter} | ||||||
|  | @ -133,24 +130,44 @@ export const ChatMessage: FC<Props> = memo( | ||||||
|                   </div> |                   </div> | ||||||
|                 )} |                 )} | ||||||
| 
 | 
 | ||||||
|                 {(isHovering || window.innerWidth < 640) && !isEditing && ( |                 {(window.innerWidth < 640 || !isEditing) && ( | ||||||
|                   <button |                   <button | ||||||
|                     className={`absolute ${ |                     className={`absolute translate-x-[1000px] text-gray-500 hover:text-gray-700 focus:translate-x-0 group-hover:translate-x-0 dark:text-gray-400 dark:hover:text-gray-300 ${ | ||||||
|                       window.innerWidth < 640 |                       window.innerWidth < 640 | ||||||
|                         ? 'right-3 bottom-1' |                         ? 'right-3 bottom-1' | ||||||
|                         : 'right-0 top-[26px]' |                         : 'right-0 top-[26px]' | ||||||
|                     }`}
 |                     } | ||||||
|  |                     `}
 | ||||||
|  |                     onClick={toggleEditing} | ||||||
|                   > |                   > | ||||||
|                     <IconEdit |                     <IconEdit size={20} /> | ||||||
|                       size={20} |  | ||||||
|                       className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300" |  | ||||||
|                       onClick={toggleEditing} |  | ||||||
|                     /> |  | ||||||
|                   </button> |                   </button> | ||||||
|                 )} |                 )} | ||||||
|               </div> |               </div> | ||||||
|             ) : ( |             ) : ( | ||||||
|               <> |               <> | ||||||
|  |                 <div | ||||||
|  |                   className={`absolute ${ | ||||||
|  |                     window.innerWidth < 640 | ||||||
|  |                       ? 'right-3 bottom-1' | ||||||
|  |                       : 'right-0 top-[26px] m-0' | ||||||
|  |                   }`}
 | ||||||
|  |                 > | ||||||
|  |                   {messagedCopied ? ( | ||||||
|  |                     <IconCheck | ||||||
|  |                       size={20} | ||||||
|  |                       className="text-green-500 dark:text-green-400" | ||||||
|  |                     /> | ||||||
|  |                   ) : ( | ||||||
|  |                     <button | ||||||
|  |                       className="translate-x-[1000px] text-gray-500 hover:text-gray-700 focus:translate-x-0 group-hover:translate-x-0 dark:text-gray-400 dark:hover:text-gray-300" | ||||||
|  |                       onClick={copyOnClick} | ||||||
|  |                     > | ||||||
|  |                       <IconCopy size={20} /> | ||||||
|  |                     </button> | ||||||
|  |                   )} | ||||||
|  |                 </div> | ||||||
|  | 
 | ||||||
|                 <MemoizedReactMarkdown |                 <MemoizedReactMarkdown | ||||||
|                   className="prose dark:prose-invert" |                   className="prose dark:prose-invert" | ||||||
|                   remarkPlugins={[remarkGfm, remarkMath]} |                   remarkPlugins={[remarkGfm, remarkMath]} | ||||||
|  | @ -197,13 +214,6 @@ export const ChatMessage: FC<Props> = memo( | ||||||
|                 > |                 > | ||||||
|                   {message.content} |                   {message.content} | ||||||
|                 </MemoizedReactMarkdown> |                 </MemoizedReactMarkdown> | ||||||
| 
 |  | ||||||
|                 {(isHovering || window.innerWidth < 640) && ( |  | ||||||
|                   <CopyButton |  | ||||||
|                     messagedCopied={messagedCopied} |  | ||||||
|                     copyOnClick={copyOnClick} |  | ||||||
|                   /> |  | ||||||
|                 )} |  | ||||||
|               </> |               </> | ||||||
|             )} |             )} | ||||||
|           </div> |           </div> | ||||||
|  |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| import { IconCheck, IconCopy } from '@tabler/icons-react'; |  | ||||||
| import { FC } from 'react'; |  | ||||||
| 
 |  | ||||||
| type Props = { |  | ||||||
|   messagedCopied: boolean; |  | ||||||
|   copyOnClick: () => void; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export const CopyButton: FC<Props> = ({ messagedCopied, copyOnClick }) => ( |  | ||||||
|   <button |  | ||||||
|     className={`absolute ${ |  | ||||||
|       window.innerWidth < 640 ? 'right-3 bottom-1' : 'right-0 top-[26px] m-0' |  | ||||||
|     }`}
 |  | ||||||
|   > |  | ||||||
|     {messagedCopied ? ( |  | ||||||
|       <IconCheck size={20} className="text-green-500 dark:text-green-400" /> |  | ||||||
|     ) : ( |  | ||||||
|       <IconCopy |  | ||||||
|         size={20} |  | ||||||
|         className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300" |  | ||||||
|         onClick={copyOnClick} |  | ||||||
|       /> |  | ||||||
|     )} |  | ||||||
|   </button> |  | ||||||
| ); |  | ||||||
|  | @ -17,7 +17,7 @@ export const ModelSelect: FC<Props> = ({ model, models, onModelChange }) => { | ||||||
|       </label> |       </label> | ||||||
|       <div className="w-full rounded-lg border border-neutral-200 bg-transparent pr-2 text-neutral-900 dark:border-neutral-600 dark:text-white"> |       <div className="w-full rounded-lg border border-neutral-200 bg-transparent pr-2 text-neutral-900 dark:border-neutral-600 dark:text-white"> | ||||||
|         <select |         <select | ||||||
|           className="w-full bg-transparent p-2 outline-0" |           className="w-full bg-transparent p-2" | ||||||
|           placeholder={t('Select a model') || ''} |           placeholder={t('Select a model') || ''} | ||||||
|           value={model.id} |           value={model.id} | ||||||
|           onChange={(e) => { |           onChange={(e) => { | ||||||
|  |  | ||||||
|  | @ -19,13 +19,7 @@ export const PromptList: FC<Props> = ({ | ||||||
|   return ( |   return ( | ||||||
|     <ul |     <ul | ||||||
|       ref={promptListRef} |       ref={promptListRef} | ||||||
|       className="z-10 w-full rounded border border-black/10 bg-white shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-neutral-500 dark:bg-[#343541] dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)]" |       className="z-10 w-full rounded border border-black/10 bg-white shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-neutral-500 dark:bg-[#343541] dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] max-h-52 overflow-scroll" | ||||||
|       style={{ |  | ||||||
|         width: 'calc(100% - 48px)', |  | ||||||
|         bottom: '100%', |  | ||||||
|         marginBottom: '4px', |  | ||||||
|         maxHeight: '200px', |  | ||||||
|       }} |  | ||||||
|     > |     > | ||||||
|       {prompts.map((prompt, index) => ( |       {prompts.map((prompt, index) => ( | ||||||
|         <li |         <li | ||||||
|  |  | ||||||
|  | @ -14,10 +14,10 @@ export const Regenerate: FC<Props> = ({ onRegenerate }) => { | ||||||
|         {t('Sorry, there was an error.')} |         {t('Sorry, there was an error.')} | ||||||
|       </div> |       </div> | ||||||
|       <button |       <button | ||||||
|         className="flex h-12 w-full items-center justify-center rounded-lg border border-b-neutral-300 bg-neutral-100 text-sm font-semibold text-neutral-500 dark:border-none dark:bg-[#444654] dark:text-neutral-200" |         className="flex h-12 gap-2 w-full items-center justify-center rounded-lg border border-b-neutral-300 bg-neutral-100 text-sm font-semibold text-neutral-500 dark:border-none dark:bg-[#444654] dark:text-neutral-200" | ||||||
|         onClick={onRegenerate} |         onClick={onRegenerate} | ||||||
|       > |       > | ||||||
|         <IconRefresh className="mr-2" /> |         <IconRefresh /> | ||||||
|         <div>{t('Regenerate response')}</div> |         <div>{t('Regenerate response')}</div> | ||||||
|       </button> |       </button> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  | @ -196,7 +196,7 @@ export const SystemPrompt: FC<Props> = ({ | ||||||
|       </label> |       </label> | ||||||
|       <textarea |       <textarea | ||||||
|         ref={textareaRef} |         ref={textareaRef} | ||||||
|         className="w-full rounded-lg border border-neutral-200 bg-transparent px-4 py-3 text-neutral-900 focus:outline-none dark:border-neutral-600 dark:text-neutral-100" |         className="w-full rounded-lg border border-neutral-200 bg-transparent px-4 py-3 text-neutral-900 dark:border-neutral-600 dark:text-neutral-100" | ||||||
|         style={{ |         style={{ | ||||||
|           resize: 'none', |           resize: 'none', | ||||||
|           bottom: `${textareaRef?.current?.scrollHeight}px`, |           bottom: `${textareaRef?.current?.scrollHeight}px`, | ||||||
|  |  | ||||||
|  | @ -194,11 +194,9 @@ export const Chatbar: FC<Props> = ({ | ||||||
|             /> |             /> | ||||||
|           </div> |           </div> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <div className="mt-8 select-none text-center text-white opacity-50"> |           <div className="flex flex-col gap-3 items-center text-sm leading-normal mt-8 text-white opacity-50"> | ||||||
|             <IconMessagesOff className="mx-auto mb-3" /> |             <IconMessagesOff /> | ||||||
|             <span className="text-[14px] leading-normal"> |  | ||||||
|               {t('No conversations.')} |               {t('No conversations.')} | ||||||
|             </span> |  | ||||||
|           </div> |           </div> | ||||||
|         )} |         )} | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|  | @ -64,18 +64,18 @@ export const CodeBlock: FC<Props> = memo(({ language, value }) => { | ||||||
| 
 | 
 | ||||||
|         <div className="flex items-center"> |         <div className="flex items-center"> | ||||||
|           <button |           <button | ||||||
|             className="flex items-center rounded bg-none py-0.5 px-2 text-xs text-white focus:outline-none" |             className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-white" | ||||||
|             onClick={copyToClipboard} |             onClick={copyToClipboard} | ||||||
|           > |           > | ||||||
|             {isCopied ? ( |             {isCopied ? ( | ||||||
|               <IconCheck size={18} className="mr-1.5" /> |               <IconCheck size={18} /> | ||||||
|             ) : ( |             ) : ( | ||||||
|               <IconClipboard size={18} className="mr-1.5" /> |               <IconClipboard size={18} /> | ||||||
|             )} |             )} | ||||||
|             {isCopied ? t('Copied!') : t('Copy code')} |             {isCopied ? t('Copied!') : t('Copy code')} | ||||||
|           </button> |           </button> | ||||||
|           <button |           <button | ||||||
|             className="flex items-center rounded bg-none py-0.5 pl-2 text-xs text-white focus:outline-none" |             className="flex items-center rounded bg-none p-1 text-xs text-white" | ||||||
|             onClick={downloadAsFile} |             onClick={downloadAsFile} | ||||||
|           > |           > | ||||||
|             <IconDownload size={18} /> |             <IconDownload size={18} /> | ||||||
|  |  | ||||||
|  | @ -655,21 +655,24 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => { | ||||||
|                   onImportConversations={handleImportConversations} |                   onImportConversations={handleImportConversations} | ||||||
|                 /> |                 /> | ||||||
| 
 | 
 | ||||||
|                 <IconArrowBarLeft |                 <button | ||||||
|                   className="fixed top-5 left-[270px] z-50 h-7 w-7 cursor-pointer hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:left-[270px] sm:h-8 sm:w-8 sm:text-neutral-700" |                   className="fixed top-5 left-[270px] z-50 h-7 w-7 hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:left-[270px] sm:h-8 sm:w-8 sm:text-neutral-700" | ||||||
|                   onClick={handleToggleChatbar} |                   onClick={handleToggleChatbar} | ||||||
|                 /> |                 > | ||||||
| 
 |                   <IconArrowBarLeft /> | ||||||
|  |                 </button> | ||||||
|                 <div |                 <div | ||||||
|                   onClick={handleToggleChatbar} |                   onClick={handleToggleChatbar} | ||||||
|                   className="absolute top-0 left-0 z-10 h-full w-full bg-black opacity-70 sm:hidden" |                   className="absolute top-0 left-0 z-10 h-full w-full bg-black opacity-70 sm:hidden" | ||||||
|                 ></div> |                 ></div> | ||||||
|               </div> |               </div> | ||||||
|             ) : ( |             ) : ( | ||||||
|               <IconArrowBarRight |               <button | ||||||
|                 className="fixed top-2.5 left-4 z-50 h-7 w-7 cursor-pointer text-white hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:left-4 sm:h-8 sm:w-8 sm:text-neutral-700" |                 className="fixed top-2.5 left-4 z-50 h-7 w-7 text-white hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:left-4 sm:h-8 sm:w-8 sm:text-neutral-700" | ||||||
|                 onClick={handleToggleChatbar} |                 onClick={handleToggleChatbar} | ||||||
|               /> |               > | ||||||
|  |                 <IconArrowBarRight /> | ||||||
|  |               </button> | ||||||
|             )} |             )} | ||||||
| 
 | 
 | ||||||
|             <div className="flex flex-1"> |             <div className="flex flex-1"> | ||||||
|  | @ -702,20 +705,24 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => { | ||||||
|                   onDeleteFolder={handleDeleteFolder} |                   onDeleteFolder={handleDeleteFolder} | ||||||
|                   onUpdateFolder={handleUpdateFolder} |                   onUpdateFolder={handleUpdateFolder} | ||||||
|                 /> |                 /> | ||||||
|                 <IconArrowBarRight |                 <button | ||||||
|                   className="fixed top-5 right-[270px] z-50 h-7 w-7 cursor-pointer hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:right-[270px] sm:h-8 sm:w-8 sm:text-neutral-700" |                   className="fixed top-5 right-[270px] z-50 h-7 w-7 hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:right-[270px] sm:h-8 sm:w-8 sm:text-neutral-700" | ||||||
|                   onClick={handleTogglePromptbar} |                   onClick={handleTogglePromptbar} | ||||||
|                 /> |                 > | ||||||
|  |                   <IconArrowBarRight /> | ||||||
|  |                 </button> | ||||||
|                 <div |                 <div | ||||||
|                   onClick={handleTogglePromptbar} |                   onClick={handleTogglePromptbar} | ||||||
|                   className="absolute top-0 left-0 z-10 h-full w-full bg-black opacity-70 sm:hidden" |                   className="absolute top-0 left-0 z-10 h-full w-full bg-black opacity-70 sm:hidden" | ||||||
|                 ></div> |                 ></div> | ||||||
|               </div> |               </div> | ||||||
|             ) : ( |             ) : ( | ||||||
|               <IconArrowBarLeft |               <button | ||||||
|                 className="fixed top-2.5 right-4 z-50 h-7 w-7 cursor-pointer text-white hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:right-4 sm:h-8 sm:w-8 sm:text-neutral-700" |                 className="fixed top-2.5 right-4 z-50 h-7 w-7 text-white hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:right-4 sm:h-8 sm:w-8 sm:text-neutral-700" | ||||||
|                 onClick={handleTogglePromptbar} |                 onClick={handleTogglePromptbar} | ||||||
|               /> |               > | ||||||
|  |                 <IconArrowBarLeft /> | ||||||
|  |               </button> | ||||||
|             )} |             )} | ||||||
|           </div> |           </div> | ||||||
|         </main> |         </main> | ||||||
|  |  | ||||||
|  | @ -9,5 +9,10 @@ module.exports = { | ||||||
|   theme: { |   theme: { | ||||||
|     extend: {}, |     extend: {}, | ||||||
|   }, |   }, | ||||||
|  |   variants: { | ||||||
|  |     extend: { | ||||||
|  |       visibility: ["group-hover"], | ||||||
|  |     }, | ||||||
|  |    }, | ||||||
|   plugins: [require('@tailwindcss/typography')], |   plugins: [require('@tailwindcss/typography')], | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue