diff --git a/frontend/src/Hero.tsx b/frontend/src/Hero.tsx index a000ab2e..e515af16 100644 --- a/frontend/src/Hero.tsx +++ b/frontend/src/Hero.tsx @@ -37,12 +37,14 @@ export default function Hero({ diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index bba83037..6195baa9 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -240,7 +240,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { ref={navRef} className={`${ !navOpen && '-ml-96 md:-ml-[18rem]' - } duration-20 fixed top-0 z-20 flex h-full w-72 flex-col border-r-[1px] border-b-0 bg-white transition-all dark:border-r-purple-taupe dark:bg-chinese-black dark:text-white`} + } duration-20 fixed top-0 z-20 flex h-full w-72 flex-col border-r-[1px] border-b-0 bg-lotion dark:bg-chinese-black transition-all dark:border-r-purple-taupe dark:text-white`} >
`${ - isActive ? 'bg-gray-3000 dark:bg-transparent' : '' - } group sticky mx-4 mt-4 flex cursor-pointer gap-2.5 rounded-3xl border border-silver p-3 hover:border-rainy-gray hover:bg-gray-3000 dark:border-purple-taupe dark:text-white dark:hover:bg-transparent` + isActive ? 'bg-transparent' : '' + } group sticky mx-4 mt-4 flex cursor-pointer gap-2.5 rounded-3xl border border-silver p-3 hover:border-rainy-gray dark:border-purple-taupe dark:text-white hover:bg-transparent` } >
-
+
Upload document { setUploadModalState('ACTIVE'); @@ -385,7 +387,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { Settings

{t('settings.label')} diff --git a/frontend/src/assets/eye-view.svg b/frontend/src/assets/eye-view.svg new file mode 100644 index 00000000..1e569cfd --- /dev/null +++ b/frontend/src/assets/eye-view.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/sync.svg b/frontend/src/assets/sync.svg index 003dec43..4733bbdb 100644 --- a/frontend/src/assets/sync.svg +++ b/frontend/src/assets/sync.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/frontend/src/assets/user.png b/frontend/src/assets/user.png deleted file mode 100644 index 3cc5d2f1..00000000 Binary files a/frontend/src/assets/user.png and /dev/null differ diff --git a/frontend/src/assets/user.svg b/frontend/src/assets/user.svg new file mode 100644 index 00000000..970bffb5 --- /dev/null +++ b/frontend/src/assets/user.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/components/ContextMenu.tsx b/frontend/src/components/ContextMenu.tsx new file mode 100644 index 00000000..96497482 --- /dev/null +++ b/frontend/src/components/ContextMenu.tsx @@ -0,0 +1,132 @@ +import { SyntheticEvent, useRef, useEffect, CSSProperties } from 'react'; + +export interface MenuOption { + icon?: string; + label: string; + onClick: (event: SyntheticEvent) => void; + variant?: 'primary' | 'danger'; + iconClassName?: string; + iconWidth?: number; + iconHeight?: number; +} + +interface ContextMenuProps { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + options: MenuOption[]; + anchorRef: React.RefObject; + className?: string; + position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'; + offset?: { x: number; y: number }; +} + +export default function ContextMenu({ + isOpen, + setIsOpen, + options, + anchorRef, + className = '', + position = 'bottom-right', + offset = { x: 0, y: 8 }, +}: ContextMenuProps) { + const menuRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + menuRef.current && + !menuRef.current.contains(event.target as Node) && + !anchorRef.current?.contains(event.target as Node) + ) { + setIsOpen(false); + } + }; + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + return () => + document.removeEventListener('mousedown', handleClickOutside); + } + }, [isOpen, setIsOpen]); + + if (!isOpen) return null; + + const getMenuPosition = (): CSSProperties => { + if (!anchorRef.current) return {}; + + const rect = anchorRef.current.getBoundingClientRect(); + const scrollY = window.scrollY || document.documentElement.scrollTop; + const scrollX = window.scrollX || document.documentElement.scrollLeft; + + let top = rect.bottom + scrollY + offset.y; + let left = rect.right + scrollX + offset.x; + + switch (position) { + case 'bottom-left': + left = rect.left + scrollX - offset.x; + break; + case 'top-right': + top = rect.top + scrollY - offset.y; + break; + case 'top-left': + top = rect.top + scrollY - offset.y; + left = rect.left + scrollX - offset.x; + break; + // bottom-right is default + } + + return { + position: 'fixed', + top: `${top}px`, + left: `${left}px`, + }; + }; + + return ( +

e.stopPropagation()} + > +
+ {options.map((option, index) => ( + + ))} +
+
+ ); +} diff --git a/frontend/src/components/CopyButton.tsx b/frontend/src/components/CopyButton.tsx index f0559f52..c430603f 100644 --- a/frontend/src/components/CopyButton.tsx +++ b/frontend/src/components/CopyButton.tsx @@ -1,18 +1,22 @@ import copy from 'copy-to-clipboard'; import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import CheckMark from '../assets/checkmark.svg?react'; import Copy from '../assets/copy.svg?react'; -export default function CoppyButton({ +export default function CopyButton({ text, colorLight, colorDark, + showText = false, }: { text: string; colorLight?: string; colorDark?: string; + showText?: boolean; }) { + const { t } = useTranslation(); const [copied, setCopied] = useState(false); const [isCopyHovered, setIsCopyHovered] = useState(false); @@ -25,29 +29,30 @@ export default function CoppyButton({ }; return ( -
handleCopyClick(text)} + onMouseEnter={() => setIsCopyHovered(true)} + onMouseLeave={() => setIsCopyHovered(false)} + className="flex items-center gap-2" > - {copied ? ( - setIsCopyHovered(true)} - onMouseLeave={() => setIsCopyHovered(false)} - /> - ) : ( - { - handleCopyClick(text); - }} - onMouseEnter={() => setIsCopyHovered(true)} - onMouseLeave={() => setIsCopyHovered(false)} - /> +
+ {copied ? ( + + ) : ( + + )} +
+ {showText && ( + + {copied ? t('conversation.copied') : t('conversation.copy')} + )} -
+ ); } diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index 5932933e..f8783aad 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -11,6 +11,7 @@ function Dropdown({ rounded = 'xl', border = 'border-2', borderColor = 'silver', + darkBorderColor = 'dim-gray', showEdit, onEdit, showDelete, @@ -38,6 +39,7 @@ function Dropdown({ rounded?: 'xl' | '3xl'; border?: 'border' | 'border-2'; borderColor?: string; + darkBorderColor?: string; showEdit?: boolean; onEdit?: (value: { name: string; id: string; type: string }) => void; showDelete?: boolean; @@ -77,7 +79,7 @@ function Dropdown({ > {isOpen && (
{options.map((option: any, index) => (
void; defaultValue?: string; icon?: string; + isOpen?: boolean; + onOpenChange?: (isOpen: boolean) => void; + anchorRef?: React.RefObject; + className?: string; + position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'; + offset?: { x: number; y: number }; }; export default function DropdownMenu({ @@ -14,24 +21,33 @@ export default function DropdownMenu({ onSelect, defaultValue = 'none', icon, + isOpen: controlledIsOpen, + onOpenChange, + anchorRef, + className = '', + position = 'bottom-right', + offset = { x: 0, y: 8 }, }: DropdownMenuProps) { const dropdownRef = React.useRef(null); - const [isOpen, setIsOpen] = React.useState(false); + const [internalIsOpen, setInternalIsOpen] = React.useState(false); const [selectedOption, setSelectedOption] = React.useState( options.find((option) => option.value === defaultValue) || options[0], ); - const handleToggle = () => { - setIsOpen(!isOpen); - }; + const isOpen = + controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen; + const setIsOpen = onOpenChange || setInternalIsOpen; + const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) + !dropdownRef.current.contains(event.target as Node) && + !anchorRef?.current?.contains(event.target as Node) ) { setIsOpen(false); } }; + const handleClickOption = (optionId: number) => { setIsOpen(false); setSelectedOption(options[optionId]); @@ -39,26 +55,40 @@ export default function DropdownMenu({ }; React.useEffect(() => { - document.addEventListener('mousedown', handleClickOutside); - return () => { - document.removeEventListener('mousedown', handleClickOutside); + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + return () => + document.removeEventListener('mousedown', handleClickOutside); + } + }, [isOpen]); + + if (!isOpen) return null; + + const getMenuPosition = (): React.CSSProperties => { + if (!anchorRef?.current) return {}; + + const rect = anchorRef.current.getBoundingClientRect(); + + const top = rect.bottom + offset.y; + const left = rect.right + offset.x; + + return { + position: 'fixed', + top: `${top}px`, + left: `${left}px`, + zIndex: 9999, }; - }, []); - return ( -
- + }; + + // Use a portal to render the dropdown outside the table flow + return ReactDOM.createPortal( +
e.stopPropagation()} + >
-
+
, + document.body, ); } diff --git a/frontend/src/components/Input.tsx b/frontend/src/components/Input.tsx index e703ff14..39dff2b0 100644 --- a/frontend/src/components/Input.tsx +++ b/frontend/src/components/Input.tsx @@ -1,4 +1,5 @@ import { InputProps } from './types'; +import { useRef } from 'react'; const Input = ({ id, @@ -7,13 +8,13 @@ const Input = ({ value, isAutoFocused = false, placeholder, - label, required = false, maxLength, - className, + className = '', colorVariant = 'silver', borderVariant = 'thick', children, + labelBgClassName = 'bg-white dark:bg-raisin-black', onChange, onPaste, onKeyDown, @@ -27,15 +28,27 @@ const Input = ({ thin: 'border', thick: 'border-2', }; + + const inputRef = useRef(null); + return ( -
+
{children} - {label && ( -
- - {label} - {required && ( - - * - - )} - -
+ {placeholder && ( + )}
); diff --git a/frontend/src/components/SettingsBar.tsx b/frontend/src/components/SettingsBar.tsx index 17e7bf5e..bd6468e9 100644 --- a/frontend/src/components/SettingsBar.tsx +++ b/frontend/src/components/SettingsBar.tsx @@ -77,8 +77,8 @@ const SettingsBar = ({ setActiveTab, activeTab }: SettingsBarProps) => { onClick={() => setActiveTab(tab)} className={`snap-start h-9 rounded-3xl px-4 font-bold transition-colors ${ activeTab === tab - ? 'bg-neutral-200 text-neutral-900 dark:bg-dark-charcoal dark:text-white' - : 'text-neutral-700 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white' + ? 'bg-[#F4F4F5] text-neutral-900 dark:bg-dark-charcoal dark:text-white' + : 'text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white' }`} role="tab" aria-selected={activeTab === tab} diff --git a/frontend/src/components/SourceDropdown.tsx b/frontend/src/components/SourceDropdown.tsx index 080ad320..a3f1b38d 100644 --- a/frontend/src/components/SourceDropdown.tsx +++ b/frontend/src/components/SourceDropdown.tsx @@ -54,7 +54,7 @@ function SourceDropdown({
{isShareModalOpen && ( - { - setShareModalState(false); - }} - conversationId={conversationId} - /> +
+
+
+ { + setShareModalState(false); + }} + conversationId={conversationId} + /> +
+
)}
)} @@ -382,10 +386,10 @@ export default function Conversation() { )}
-
+
-

+

{t('tagline')}

diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 3ebf46b4..8638718f 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -5,10 +5,14 @@ import { useTranslation } from 'react-i18next'; import ReactMarkdown from 'react-markdown'; import { useSelector } from 'react-redux'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; +import { + vscDarkPlus, + oneLight, +} from 'react-syntax-highlighter/dist/cjs/styles/prism'; import rehypeKatex from 'rehype-katex'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; +import { useDarkTheme } from '../hooks'; import DocsGPT3 from '../assets/cute_docsgpt3.svg'; import ChevronDown from '../assets/chevron-down.svg'; @@ -18,7 +22,7 @@ import Edit from '../assets/edit.svg'; import Like from '../assets/like.svg?react'; import Link from '../assets/link.svg'; import Sources from '../assets/sources.svg'; -import UserIcon from '../assets/user.png'; +import UserIcon from '../assets/user.svg'; import Accordion from '../components/Accordion'; import Avatar from '../components/Avatar'; import CopyButton from '../components/CopyButton'; @@ -69,6 +73,7 @@ const ConversationBubble = forwardRef< ref, ) { const { t } = useTranslation(); + const [isDarkTheme] = useDarkTheme(); // const bubbleRef = useRef(null); const chunks = useSelector(selectChunks); const selectedDocs = useSelector(selectSelectedDocs); @@ -113,7 +118,7 @@ const ConversationBubble = forwardRef< style={{ wordBreak: 'break-word', }} - className="text-sm sm:text-base ml-2 mr-2 flex items-center rounded-[28px] bg-purple-30 py-[14px] px-[19px] text-white max-w-full whitespace-pre-wrap leading-normal" + className="text-sm sm:text-base ml-2 mr-2 flex items-center rounded-[28px] bg-gradient-to-b from-medium-purple to-slate-blue py-[14px] px-[19px] text-white max-w-full whitespace-pre-wrap leading-normal" > {message}
@@ -122,7 +127,7 @@ const ConversationBubble = forwardRef< setIsEditClicked(true); setEditInputBox(message); }} - className={`flex-shrink-0 h-fit mt-3 p-2 cursor-pointer rounded-full hover:bg-[#35363B] flex items-center ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`} + className={`flex-shrink-0 h-fit mt-3 p-2 cursor-pointer rounded-full hover:bg-light-silver dark:hover:bg-[#35363B] flex items-center ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`} > Edit @@ -138,29 +143,29 @@ const ConversationBubble = forwardRef< onChange={(e) => { setEditInputBox(e.target.value); }} - onKeyDown={(e) => { - if(e.key === 'Enter' && !e.shiftKey){ - e.preventDefault(); + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); handleEditClick(); } }} rows={5} value={editInputBox} - className="w-full resize-none border-2 border-black dark:border-white rounded-3xl px-4 py-3 text-base leading-relaxed text-black dark:bg-raisin-black dark:text-white focus:outline-none focus:ring-2 focus:ring-[#CDB5FF]" + className="w-full resize-none border border-silver dark:border-philippine-grey rounded-3xl px-4 py-3 text-base leading-relaxed text-carbon dark:text-chinese-white dark:bg-raisin-black focus:outline-none" />
- +
)} @@ -341,7 +346,7 @@ const ConversationBubble = forwardRef<

- - {String(children).replace(/\n$/, '')} - -
+
+
+ + {language} +
+ + {String(children).replace(/\n$/, '')} +
) : ( diff --git a/frontend/src/conversation/ConversationTile.tsx b/frontend/src/conversation/ConversationTile.tsx index c29b9d71..c9efcd02 100644 --- a/frontend/src/conversation/ConversationTile.tsx +++ b/frontend/src/conversation/ConversationTile.tsx @@ -18,6 +18,9 @@ import { selectConversationId } from '../preferences/preferenceSlice'; import { ActiveState } from '../models/misc'; import { ShareConversationModal } from '../modals/ShareConversationModal'; import { useTranslation } from 'react-i18next'; +import ContextMenu from '../components/ContextMenu'; +import { MenuOption } from '../components/ContextMenu'; +import { useOutsideAlerter } from '../hooks'; interface ConversationProps { name: string; @@ -128,6 +131,50 @@ export default function ConversationTile({ } }; + const menuOptions: MenuOption[] = [ + { + icon: Share, + label: t('convTile.share'), + onClick: (event: SyntheticEvent) => { + event.stopPropagation(); + setShareModalState(true); + setOpen(false); + }, + variant: 'primary', + iconWidth: 14, + iconHeight: 14, + }, + { + icon: Edit, + label: t('convTile.rename'), + onClick: handleEditConversation, + variant: 'primary', + }, + { + icon: Trash, + label: t('convTile.delete'), + onClick: (event: SyntheticEvent) => { + event.stopPropagation(); + setDeleteModalState('ACTIVE'); + setOpen(false); + }, + iconWidth: 18, + iconHeight: 18, + variant: 'danger', + }, + ]; + + useOutsideAlerter( + tileRef, + () => { + if (isEdit) { + onClear(); + } + }, + [isEdit], + true, + ); + return ( <>
{ - setIsHovered(false); + if (!isEdit) { + setIsHovered(false); + } }} onClick={() => { onCoversationClick(); conversationId !== conversation.id && selectConversation(conversation.id); }} - className={`my-auto mx-4 mt-4 flex h-9 cursor-pointer items-center justify-between pl-4 gap-4 rounded-3xl hover:bg-gray-100 dark:hover:bg-[#28292E] ${ - conversationId === conversation.id || isOpen || isHovered - ? 'bg-gray-100 dark:bg-[#28292E]' + className={`my-auto mx-4 mt-4 flex h-9 cursor-pointer items-center justify-between pl-4 gap-4 rounded-3xl hover:bg-bright-gray dark:hover:bg-dark-charcoal ${ + conversationId === conversation.id || isOpen || isHovered || isEdit + ? 'bg-bright-gray dark:bg-dark-charcoal' : '' }`} > @@ -160,13 +209,13 @@ export default function ConversationTile({ onKeyDown={handleRenameKeyDown} /> ) : ( -

+

{conversationName}

)}
{(conversationId === conversation.id || isHovered || isOpen) && ( -
+
{isEdit ? (
)} - {isOpen && ( -
- - - -
- )} +
)}
diff --git a/frontend/src/conversation/sharedConversationSlice.ts b/frontend/src/conversation/sharedConversationSlice.ts index bef306dd..7ae4862b 100644 --- a/frontend/src/conversation/sharedConversationSlice.ts +++ b/frontend/src/conversation/sharedConversationSlice.ts @@ -231,8 +231,7 @@ export const sharedConversationSlice = createSlice({ return state; } state.status = 'failed'; - state.queries[state.queries.length - 1].error = - 'Something went wrong. Please check your internet connection.'; + state.queries[state.queries.length - 1].error = 'Something went wrong'; }); }, }); diff --git a/frontend/src/index.css b/frontend/src/index.css index 85d6fced..88e56469 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -485,25 +485,31 @@ template { ::-webkit-scrollbar { width: 10; } - -input:-webkit-autofill { - -webkit-box-shadow: 0 0 0 50px white inset; +/* Light mode specific autofill styles */ +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +input:-webkit-autofill:active { + -webkit-text-fill-color: #343541 !important; + -webkit-box-shadow: 0 0 0 30px transparent inset !important; + transition: background-color 5000s ease-in-out 0s; + caret-color: #343541; } -input:-webkit-autofill:focus { - -webkit-box-shadow: 0 0 0 50px white inset; +/* Dark mode specific autofill styles */ +.dark input:-webkit-autofill, +.dark input:-webkit-autofill:hover, +.dark input:-webkit-autofill:focus, +.dark input:-webkit-autofill:active { + -webkit-text-fill-color: #E5E7EB !important; + -webkit-box-shadow: 0 0 0 30px transparent inset !important; + background-color: transparent !important; + caret-color: #E5E7EB; } -@media (prefers-color-scheme: dark) { - input:-webkit-autofill { - -webkit-box-shadow: 0 0 0 50px rgb(68, 70, 84) inset; - -webkit-text-fill-color: white; - } - - input:-webkit-autofill:focus { - -webkit-box-shadow: 0 0 0 50px rgb(68, 70, 84) inset; - -webkit-text-fill-color: white; - } +/* Additional autocomplete dropdown styles for dark mode */ +.dark input:-webkit-autofill::first-line { + color: #E5E7EB; } .inputbox-style { diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 1081ddf0..54f6f441 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -50,7 +50,8 @@ "medium": "Medium", "high": "High", "unlimited": "Unlimited", - "default": "Default" + "default": "Default", + "add": "Add" }, "documents": { "title": "This table contains all the documents that are available to you and those you have uploaded", @@ -72,6 +73,7 @@ "monthly": "Monthly" }, "actions": "Actions", + "view": "View", "deleteWarning": "Are you sure you want to delete \"{{name}}\"?" }, "apiKeys": { @@ -97,7 +99,7 @@ }, "messages": "Messages", "tokenUsage": "Token Usage", - "feedback": "Feedback", + "userFeedback": "User Feedback", "filterPlaceholder": "Filter", "none": "None", "positiveFeedback": "Positive Feedback", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index e699a3c6..fc5532bb 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -43,7 +43,7 @@ "prompt": "Prompt Activo", "deleteAllLabel": "Eliminar todas las conversaciones", "deleteAllBtn": "Eliminar todo", - "addNew": "Agregar Nuevo", + "add": "Añadir", "convHistory": "Historial de conversaciones", "none": "Ninguno", "low": "Bajo", @@ -72,6 +72,7 @@ "monthly": "Mensual" }, "actions": "Acciones", + "view": "Ver", "deleteWarning": "¿Estás seguro de que deseas eliminar \"{{name}}\"?" }, "apiKeys": { @@ -97,7 +98,7 @@ }, "messages": "Mensajes", "tokenUsage": "Uso de Tokens", - "feedback": "Retroalimentación", + "userFeedback": "Retroalimentación del Usuario", "filterPlaceholder": "Filtrar", "none": "Ninguno", "positiveFeedback": "Retroalimentación Positiva", diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 7c716135..10ee9989 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -50,7 +50,8 @@ "medium": "中", "high": "高", "unlimited": "無制限", - "default": "デフォルト" + "default": "デフォルト", + "add": "追加" }, "documents": { "label": "ドキュメント", @@ -71,6 +72,7 @@ "monthly": "毎月" }, "actions": "アクション", + "view": "表示", "deleteWarning": "\"{{name}}\"を削除してもよろしいですか?" }, "apiKeys": { @@ -100,7 +102,8 @@ "filterPlaceholder": "フィルター", "none": "なし", "positiveFeedback": "肯定的なフィードバック", - "negativeFeedback": "否定的なフィードバック" + "negativeFeedback": "否定的なフィードバック", + "userFeedback": "ユーザーフィードバック" }, "logs": { "label": "ログ", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index 3ec75bfb..f265ea08 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -50,7 +50,8 @@ "medium": "Средний", "high": "Высокий", "unlimited": "Без ограничений", - "default": "По умолчанию" + "default": "По умолчанию", + "add": "Добавить" }, "documents": { "title": "Эта таблица содержит все документы, которые доступны вам и те, которые вы загрузили", @@ -72,6 +73,7 @@ "monthly": "Ежемесячно" }, "actions": "Действия", + "view": "Просмотр", "deleteWarning": "Вы уверены, что хотите удалить \"{{name}}\"?" }, "apiKeys": { @@ -97,7 +99,7 @@ }, "messages": "Сообщения", "tokenUsage": "Использование токена", - "feedback": "Обратная связь", + "userFeedback": "Обратная Связь Пользователя", "filterPlaceholder": "Фильтр", "none": "Нет", "positiveFeedback": "Положительная обратная связь", diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index eb0240a0..97478172 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -50,7 +50,8 @@ "medium": "中", "high": "高", "unlimited": "無限制", - "default": "預設" + "default": "預設", + "add": "添加" }, "documents": { "title": "此表格包含所有可供您使用的文件以及您上傳的文件", @@ -72,6 +73,7 @@ "monthly": "每月" }, "actions": "操作", + "view": "查看", "deleteWarning": "您確定要刪除 \"{{name}}\" 嗎?" }, "apiKeys": { @@ -97,7 +99,7 @@ }, "messages": "訊息", "tokenUsage": "Token 使用量", - "feedback": "回饋", + "userFeedback": "使用者反饋", "filterPlaceholder": "篩選", "none": "無", "positiveFeedback": "正向回饋", diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 245333c3..20a216d2 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -50,7 +50,8 @@ "medium": "中", "high": "高", "unlimited": "无限", - "default": "默认" + "default": "默认", + "add": "添加" }, "documents": { "title": "此表格包含所有可供您使用的文档以及您上传的文档", @@ -72,6 +73,7 @@ "monthly": "每月" }, "actions": "操作", + "view": "查看", "deleteWarning": "您确定要删除 \"{{name}}\" 吗?" }, "apiKeys": { @@ -97,7 +99,7 @@ }, "messages": "消息", "tokenUsage": "令牌使用", - "feedback": "反馈", + "userFeedback": "用户反馈", "filterPlaceholder": "筛选", "none": "无", "positiveFeedback": "正向反馈", diff --git a/frontend/src/modals/AddActionModal.tsx b/frontend/src/modals/AddActionModal.tsx index c7c813c3..5db46558 100644 --- a/frontend/src/modals/AddActionModal.tsx +++ b/frontend/src/modals/AddActionModal.tsx @@ -59,6 +59,7 @@ export default function AddActionModal({ setFunctionNameError(!isValidFunctionName(value)); }} borderVariant="thin" + labelBgClassName="bg-white dark:bg-charleston-green-2" placeholder={'Enter name'} />

diff --git a/frontend/src/modals/AddToolModal.tsx b/frontend/src/modals/AddToolModal.tsx index 07360eb7..42b55d69 100644 --- a/frontend/src/modals/AddToolModal.tsx +++ b/frontend/src/modals/AddToolModal.tsx @@ -94,57 +94,60 @@ export default function AddToolModal({ {modalState === 'ACTIVE' && ( setModalState('INACTIVE')} - className="h-[85vh] w-[90vw] md:w-[75vw]" + className="max-w-[950px] w-[90vw] md:w-[85vw] lg:w-[75vw] h-[85vh]" > -

+

{t('settings.tools.selectToolSetup')}

-
+
{loading ? ( -
+
) : ( - availableTools.map((tool, index) => ( -
{ - setSelectedTool(tool); - handleAddTool(tool); - }} - onKeyDown={(e) => { - if (e.key === 'Enter' || e.key === ' ') { +
+ {availableTools.map((tool, index) => ( +
{ setSelectedTool(tool); handleAddTool(tool); - } - }} - > -
-
- -
-
-

- {tool.displayName} -

-

- {tool.description} -

+ }} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + setSelectedTool(tool); + handleAddTool(tool); + } + }} + > +
+
+ {`${tool.name} +
+
+

+ {tool.displayName} +

+

+ {tool.description} +

+
-
- )) + ))} +
)}
diff --git a/frontend/src/modals/ChunkModal.tsx b/frontend/src/modals/ChunkModal.tsx index 83a100ee..4ef169d7 100644 --- a/frontend/src/modals/ChunkModal.tsx +++ b/frontend/src/modals/ChunkModal.tsx @@ -61,6 +61,7 @@ export default function ChunkModal({ onChange={(e) => setTitle(e.target.value)} borderVariant="thin" placeholder={'Enter title'} + labelBgClassName="bg-white dark:bg-charleston-green-2" >
@@ -83,7 +84,7 @@ export default function ChunkModal({ handleSubmit(title, chunkText); setModalState('INACTIVE'); }} - className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-[#6F3FD1]" + className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue" > Add @@ -123,15 +124,13 @@ export default function ChunkModal({ Edit Chunk
- - Title - setTitle(e.target.value)} borderVariant="thin" placeholder={'Enter title'} + labelBgClassName="bg-white dark:bg-charleston-green-2" >
@@ -163,7 +162,7 @@ export default function ChunkModal({ handleSubmit(title, chunkText); setModalState('INACTIVE'); }} - className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-[#6F3FD1]" + className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue" > Update diff --git a/frontend/src/modals/ConfigToolModal.tsx b/frontend/src/modals/ConfigToolModal.tsx index 04553677..05517c51 100644 --- a/frontend/src/modals/ConfigToolModal.tsx +++ b/frontend/src/modals/ConfigToolModal.tsx @@ -59,7 +59,7 @@ export default function ConfigToolModal({ onChange={(e) => setAuthKey(e.target.value)} borderVariant="thin" placeholder={t('modals.configTool.apiKeyPlaceholder')} - label={t('modals.configTool.apiKeyLabel')} + labelBgClassName="bg-white dark:bg-charleston-green-2" />
@@ -67,7 +67,7 @@ export default function ConfigToolModal({ onClick={() => { tool && handleAddTool(tool); }} - className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-[#6F3FD1]" + className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue" > {t('modals.configTool.addButton')} diff --git a/frontend/src/modals/ConfirmationModal.tsx b/frontend/src/modals/ConfirmationModal.tsx index 28b9c582..25f8c2da 100644 --- a/frontend/src/modals/ConfirmationModal.tsx +++ b/frontend/src/modals/ConfirmationModal.tsx @@ -11,6 +11,7 @@ export default function ConfirmationModal({ handleSubmit, cancelLabel, handleCancel, + variant = 'default', }: { message: string; modalState: ActiveState; @@ -19,8 +20,15 @@ export default function ConfirmationModal({ handleSubmit: () => void; cancelLabel?: string; handleCancel?: () => void; + variant?: 'default' | 'danger'; }) { const { t } = useTranslation(); + + const submitButtonClasses = + variant === 'danger' + ? 'rounded-3xl bg-rosso-corsa px-5 py-2 text-sm text-lotion transition-all hover:bg-red-2000 hover:font-bold tracking-[0.019em] hover:tracking-normal' + : 'rounded-3xl bg-purple-30 px-5 py-2 text-sm text-lotion transition-all hover:bg-violets-are-blue'; + return ( <> {modalState === 'ACTIVE' && ( @@ -39,7 +47,7 @@ export default function ConfirmationModal({
diff --git a/frontend/src/modals/CreateAPIKeyModal.tsx b/frontend/src/modals/CreateAPIKeyModal.tsx index 128bdff6..a35efd60 100644 --- a/frontend/src/modals/CreateAPIKeyModal.tsx +++ b/frontend/src/modals/CreateAPIKeyModal.tsx @@ -84,9 +84,10 @@ export default function CreateAPIKeyModal({ type="text" className="rounded-md" value={APIKeyName} - label={t('modals.createAPIKey.apiKeyName')} + placeholder={t('modals.createAPIKey.apiKeyName')} onChange={(e) => setAPIKeyName(e.target.value)} borderVariant="thin" + labelBgClassName="bg-white dark:bg-charleston-green-2" >
@@ -144,7 +145,7 @@ export default function CreateAPIKeyModal({ createAPIKey(payload); } }} - className="float-right mt-4 rounded-full bg-purple-30 px-5 py-2 text-sm text-white hover:bg-[#6F3FD1] disabled:opacity-50" + className="float-right mt-4 rounded-full bg-purple-30 px-5 py-2 text-sm text-white hover:bg-violets-are-blue disabled:opacity-50" > {t('modals.createAPIKey.create')} diff --git a/frontend/src/modals/DeleteConvModal.tsx b/frontend/src/modals/DeleteConvModal.tsx index 43ec2a65..630300ad 100644 --- a/frontend/src/modals/DeleteConvModal.tsx +++ b/frontend/src/modals/DeleteConvModal.tsx @@ -42,6 +42,7 @@ export default function DeleteConvModal({ submitLabel={t('modals.deleteConv.delete')} handleSubmit={handleSubmit} handleCancel={handleCancel} + variant="danger" /> ); } diff --git a/frontend/src/modals/SaveAPIKeyModal.tsx b/frontend/src/modals/SaveAPIKeyModal.tsx index abe862cb..1e589a18 100644 --- a/frontend/src/modals/SaveAPIKeyModal.tsx +++ b/frontend/src/modals/SaveAPIKeyModal.tsx @@ -34,7 +34,7 @@ export default function SaveAPIKeyModal({
) : (