From 5097f77469a84b2ec65114c4d927f49ad2a5bfa6 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 27 May 2025 19:02:41 +0530 Subject: [PATCH 1/7] (feat:toolConfig) ui details, no actions placeholder --- frontend/src/settings/ToolConfig.tsx | 392 ++++++++++++++------------- 1 file changed, 211 insertions(+), 181 deletions(-) diff --git a/frontend/src/settings/ToolConfig.tsx b/frontend/src/settings/ToolConfig.tsx index de99fabf..53eb3984 100644 --- a/frontend/src/settings/ToolConfig.tsx +++ b/frontend/src/settings/ToolConfig.tsx @@ -16,6 +16,9 @@ import { selectToken } from '../preferences/preferenceSlice'; import { APIActionType, APIToolType, UserToolType } from './types'; import { useTranslation } from 'react-i18next'; import { areObjectsEqual } from '../utils/objectUtils'; +import { useDarkTheme } from '../hooks'; +import NoFilesIcon from '../assets/no-files.svg'; +import NoFilesDarkIcon from '../assets/no-files-dark.svg'; export default function ToolConfig({ tool, @@ -44,6 +47,7 @@ export default function ToolConfig({ const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false); const [showUnsavedModal, setShowUnsavedModal] = React.useState(false); const { t } = useTranslation(); + const [isDarkTheme] = useDarkTheme(); const handleBackClick = () => { if (hasUnsavedChanges) { @@ -211,201 +215,227 @@ export default function ToolConfig({
-
+

Actions

-
- {tool.name === 'api_tool' ? ( - <> - -
+ {tool.name === 'api_tool' && + (!tool.config.actions || + Object.keys(tool.config.actions).length === 0) && ( -
+ )} +
+ {tool.name === 'api_tool' ? ( + <> + {tool.config.actions && + Object.keys(tool.config.actions).length > 0 ? ( + + ) : ( +
+ No actions found +

+ No actions found +

+
+ )} ) : (
- {'actions' in tool && - tool.actions.map((action, actionIndex) => { - return ( -
-
-

- {action.name} -

- { - setTool({ - ...tool, - actions: tool.actions.map((act, index) => { - if (index === actionIndex) { - return { ...act, active: checked }; - } - return act; - }), - }); - }} - size="small" - id={`actionToggle-${actionIndex}`} - /> -
-
- { - setTool({ - ...tool, - actions: tool.actions.map((act, index) => { - if (index === actionIndex) { - return { - ...act, - description: e.target.value, - }; - } - return act; - }), - }); - }} - borderVariant="thin" - /> -
-
- - - - - - - - - - - - {Object.entries(action.parameters?.properties).map( - (param, index) => { - const uniqueKey = `${actionIndex}-${param[0]}`; - return ( - - - - - - - - ); - }, - )} - -
Field NameField TypeFilled by LLMFIeld descriptionValue
{param[0]}{param[1].type} - - - { - setTool({ - ...tool, - actions: tool.actions.map( - (act, index) => { - if (index === actionIndex) { - return { - ...act, - parameters: { - ...act.parameters, - properties: { - ...act.parameters - .properties, - [param[0]]: { - ...act.parameters - .properties[param[0]], - description: - e.target.value, - }, - }, - }, - }; - } - return act; - }, - ), - }); - }} - > - - { - setTool({ - ...tool, - actions: tool.actions.map( - (act, index) => { - if (index === actionIndex) { - return { - ...act, - parameters: { - ...act.parameters, - properties: { - ...act.parameters - .properties, - [param[0]]: { - ...act.parameters - .properties[param[0]], - value: e.target.value, - }, - }, - }, - }; - } - return act; - }, - ), - }); - }} - > -
-
+ {'actions' in tool && tool.actions && tool.actions.length > 0 ? ( + tool.actions.map((action, actionIndex) => ( +
+
+

+ {action.name} +

+ { + setTool({ + ...tool, + actions: tool.actions.map((act, index) => { + if (index === actionIndex) { + return { ...act, active: checked }; + } + return act; + }), + }); + }} + size="small" + id={`actionToggle-${actionIndex}`} + />
- ); - })} +
+ { + setTool({ + ...tool, + actions: tool.actions.map((act, index) => { + if (index === actionIndex) { + return { + ...act, + description: e.target.value, + }; + } + return act; + }), + }); + }} + borderVariant="thin" + /> +
+
+ + + + + + + + + + + + {Object.entries(action.parameters?.properties).map( + (param, index) => { + const uniqueKey = `${actionIndex}-${param[0]}`; + return ( + + + + + + + + ); + }, + )} + +
Field NameField TypeFilled by LLMFIeld descriptionValue
{param[0]}{param[1].type} + + + { + setTool({ + ...tool, + actions: tool.actions.map( + (act, index) => { + if (index === actionIndex) { + return { + ...act, + parameters: { + ...act.parameters, + properties: { + ...act.parameters + .properties, + [param[0]]: { + ...act.parameters + .properties[param[0]], + description: + e.target.value, + }, + }, + }, + }; + } + return act; + }, + ), + }); + }} + > + + { + setTool({ + ...tool, + actions: tool.actions.map( + (act, index) => { + if (index === actionIndex) { + return { + ...act, + parameters: { + ...act.parameters, + properties: { + ...act.parameters + .properties, + [param[0]]: { + ...act.parameters + .properties[param[0]], + value: e.target.value, + }, + }, + }, + }; + } + return act; + }, + ), + }); + }} + > +
+
+
+ )) + ) : ( +
+ No actions found +

+ No actions found +

+
+ )}
)} Date: Wed, 28 May 2025 01:10:10 +0530 Subject: [PATCH 2/7] (feat:toolConfig) i18n --- frontend/src/locale/en.json | 26 +++- frontend/src/locale/es.json | 35 ++++- frontend/src/locale/jp.json | 35 ++++- frontend/src/locale/ru.json | 37 ++++- frontend/src/locale/zh-TW.json | 39 ++++- frontend/src/locale/zh.json | 37 ++++- frontend/src/settings/ToolConfig.tsx | 206 ++++++++++++++------------- 7 files changed, 304 insertions(+), 111 deletions(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 352de717..f29f13d4 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -125,7 +125,31 @@ "deleteWarning": "Are you sure you want to delete the tool \"{{toolName}}\" ?", "unsavedChanges": "You have unsaved changes that will be lost if you leave without saving.", "leaveWithoutSaving": "Leave without Saving", - "saveAndLeave": "Save and Leave" + "saveAndLeave": "Save and Leave", + "customName": "Custom Name", + "customNamePlaceholder": "Enter a custom name (optional)", + "authentication": "Authentication", + "actions": "Actions", + "addAction": "Add action", + "noActionsFound": "No actions found", + "url": "URL", + "urlPlaceholder": "Enter url", + "method": "Method", + "description": "Description", + "descriptionPlaceholder": "Enter description", + "headers": "Headers", + "queryParameters": "Query Parameters", + "body": "Body", + "deleteActionWarning": "Are you sure you want to delete the action \"{{name}}\"?", + "backToTools": "Back to Tools", + "save": "Save", + "name": "Name", + "type": "Type", + "filledByLLM": "Filled by LLM", + "value": "Value", + "addProperty": "Add property", + "propertyName": "Property name", + "noProperties": "No properties" } }, "modals": { diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 159d56cf..fe658b92 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -116,8 +116,39 @@ "noToolsFound": "No se encontraron herramientas", "selectToolSetup": "Seleccione una herramienta para configurar", "settingsIconAlt": "Icono de configuración", - "configureToolAria": "Configurar {toolName}", - "toggleToolAria": "Alternar {toolName}" + "configureToolAria": "Configurar {{toolName}}", + "toggleToolAria": "Alternar {{toolName}}", + "manageTools": "Ir a Herramientas", + "edit": "Editar", + "delete": "Eliminar", + "deleteWarning": "¿Estás seguro de que deseas eliminar la herramienta \"{{toolName}}\"?", + "unsavedChanges": "Tienes cambios sin guardar que se perderán si sales sin guardar.", + "leaveWithoutSaving": "Salir sin Guardar", + "saveAndLeave": "Guardar y Salir", + "customName": "Nombre Personalizado", + "customNamePlaceholder": "Ingresa un nombre personalizado (opcional)", + "authentication": "Autenticación", + "actions": "Acciones", + "addAction": "Agregar acción", + "noActionsFound": "No se encontraron acciones", + "url": "URL", + "urlPlaceholder": "Ingresa url", + "method": "Método", + "description": "Descripción", + "descriptionPlaceholder": "Ingresa descripción", + "headers": "Encabezados", + "queryParameters": "Parámetros de Consulta", + "body": "Cuerpo", + "deleteActionWarning": "¿Estás seguro de que deseas eliminar la acción \"{{name}}\"?", + "backToTools": "Volver a Herramientas", + "save": "Guardar", + "name": "Nombre", + "type": "Tipo", + "filledByLLM": "Completado por LLM", + "value": "Valor", + "addProperty": "Agregar propiedad", + "propertyName": "Nombre de propiedad", + "noProperties": "Sin propiedades" } }, "modals": { diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 907513df..b768ef00 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -117,8 +117,39 @@ "noToolsFound": "ツールが見つかりません", "selectToolSetup": "設定するツールを選択してください", "settingsIconAlt": "設定アイコン", - "configureToolAria": "{toolName} を設定", - "toggleToolAria": "{toolName} を切り替え" + "configureToolAria": "{{toolName}}を設定", + "toggleToolAria": "{{toolName}}を切り替え", + "manageTools": "ツールへ移動", + "edit": "編集", + "delete": "削除", + "deleteWarning": "ツール \"{{toolName}}\" を削除してもよろしいですか?", + "unsavedChanges": "保存されていない変更があります。保存せずに離れると失われます。", + "leaveWithoutSaving": "保存せずに離れる", + "saveAndLeave": "保存して離れる", + "customName": "カスタム名", + "customNamePlaceholder": "カスタム名を入力(任意)", + "authentication": "認証", + "actions": "アクション", + "addAction": "アクションを追加", + "noActionsFound": "アクションが見つかりません", + "url": "URL", + "urlPlaceholder": "URLを入力", + "method": "メソッド", + "description": "説明", + "descriptionPlaceholder": "説明を入力", + "headers": "ヘッダー", + "queryParameters": "クエリパラメータ", + "body": "ボディ", + "deleteActionWarning": "アクション \"{{name}}\" を削除してもよろしいですか?", + "backToTools": "ツールに戻る", + "save": "保存", + "name": "名前", + "type": "タイプ", + "filledByLLM": "LLMによる入力", + "value": "値", + "addProperty": "プロパティを追加", + "propertyName": "プロパティ名", + "noProperties": "プロパティなし" } }, "modals": { diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index 05fa1e71..b2e07caf 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -116,9 +116,40 @@ "addTool": "Добавить инструмент", "noToolsFound": "Инструменты не найдены", "selectToolSetup": "Выберите инструмент для настройки", - "settingsIconAlt": "Иконка настроек", - "configureToolAria": "Настроить {toolName}", - "toggleToolAria": "Переключить {toolName}" + "settingsIconAlt": "Значок настроек", + "configureToolAria": "Настроить {{toolName}}", + "toggleToolAria": "Переключить {{toolName}}", + "manageTools": "Перейти к инструментам", + "edit": "Редактировать", + "delete": "Удалить", + "deleteWarning": "Вы уверены, что хотите удалить инструмент \"{{toolName}}\"?", + "unsavedChanges": "У вас есть несохраненные изменения, которые будут потеряны, если вы уйдете без сохранения.", + "leaveWithoutSaving": "Уйти без сохранения", + "saveAndLeave": "Сохранить и уйти", + "customName": "Пользовательское имя", + "customNamePlaceholder": "Введите пользовательское имя (необязательно)", + "authentication": "Аутентификация", + "actions": "Действия", + "addAction": "Добавить действие", + "noActionsFound": "Действия не найдены", + "url": "URL", + "urlPlaceholder": "Введите url", + "method": "Метод", + "description": "Описание", + "descriptionPlaceholder": "Введите описание", + "headers": "Заголовки", + "queryParameters": "Параметры запроса", + "body": "Тело", + "deleteActionWarning": "Вы уверены, что хотите удалить действие \"{{name}}\"?", + "backToTools": "Вернуться к инструментам", + "save": "Сохранить", + "name": "Имя", + "type": "Тип", + "filledByLLM": "Заполнено LLM", + "value": "Значение", + "addProperty": "Добавить свойство", + "propertyName": "Имя свойства", + "noProperties": "Нет свойств" } }, "modals": { diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index 7a95274e..394c2b43 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -112,13 +112,44 @@ }, "tools": { "label": "工具", - "searchPlaceholder": "搜尋...", + "searchPlaceholder": "搜尋工具...", "addTool": "新增工具", "noToolsFound": "找不到工具", "selectToolSetup": "選擇要設定的工具", - "settingsIconAlt": "設定圖標", - "configureToolAria": "配置 {toolName}", - "toggleToolAria": "切換 {toolName}" + "settingsIconAlt": "設定圖示", + "configureToolAria": "設定 {{toolName}}", + "toggleToolAria": "切換 {{toolName}}", + "manageTools": "前往工具", + "edit": "編輯", + "delete": "刪除", + "deleteWarning": "您確定要刪除工具 \"{{toolName}}\" 嗎?", + "unsavedChanges": "您有未儲存的變更,如果不儲存就離開將會遺失。", + "leaveWithoutSaving": "不儲存離開", + "saveAndLeave": "儲存並離開", + "customName": "自訂名稱", + "customNamePlaceholder": "輸入自訂名稱(選填)", + "authentication": "認證", + "actions": "操作", + "addAction": "新增操作", + "noActionsFound": "找不到操作", + "url": "URL", + "urlPlaceholder": "輸入url", + "method": "方法", + "description": "描述", + "descriptionPlaceholder": "輸入描述", + "headers": "標頭", + "queryParameters": "查詢參數", + "body": "主體", + "deleteActionWarning": "您確定要刪除操作 \"{{name}}\" 嗎?", + "backToTools": "返回工具", + "save": "儲存", + "name": "名稱", + "type": "類型", + "filledByLLM": "由LLM填寫", + "value": "值", + "addProperty": "新增屬性", + "propertyName": "屬性名稱", + "noProperties": "無屬性" } }, "modals": { diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 56ee7270..22f144dd 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -112,13 +112,44 @@ }, "tools": { "label": "工具", - "searchPlaceholder": "搜索...", + "searchPlaceholder": "搜索工具...", "addTool": "添加工具", "noToolsFound": "未找到工具", "selectToolSetup": "选择要设置的工具", "settingsIconAlt": "设置图标", - "configureToolAria": "配置 {toolName}", - "toggleToolAria": "切换 {toolName}" + "configureToolAria": "配置 {{toolName}}", + "toggleToolAria": "切换 {{toolName}}", + "manageTools": "前往工具", + "edit": "编辑", + "delete": "删除", + "deleteWarning": "您确定要删除工具 \"{{toolName}}\" 吗?", + "unsavedChanges": "您有未保存的更改,如果不保存就离开将会丢失。", + "leaveWithoutSaving": "不保存离开", + "saveAndLeave": "保存并离开", + "customName": "自定义名称", + "customNamePlaceholder": "输入自定义名称(可选)", + "authentication": "认证", + "actions": "操作", + "addAction": "添加操作", + "noActionsFound": "未找到操作", + "url": "URL", + "urlPlaceholder": "输入url", + "method": "方法", + "description": "描述", + "descriptionPlaceholder": "输入描述", + "headers": "请求头", + "queryParameters": "查询参数", + "body": "请求体", + "deleteActionWarning": "您确定要删除操作 \"{{name}}\" 吗?", + "backToTools": "返回工具", + "save": "保存", + "name": "名称", + "type": "类型", + "filledByLLM": "由LLM填充", + "value": "值", + "addProperty": "添加属性", + "propertyName": "属性名称", + "noProperties": "无属性" } }, "modals": { diff --git a/frontend/src/settings/ToolConfig.tsx b/frontend/src/settings/ToolConfig.tsx index 53eb3984..2194f93f 100644 --- a/frontend/src/settings/ToolConfig.tsx +++ b/frontend/src/settings/ToolConfig.tsx @@ -181,7 +181,7 @@ export default function ToolConfig({ {/* Custom name section */}

- Custom Name + {t('settings.tools.customName')}

setCustomName(e.target.value)} borderVariant="thin" - placeholder="Enter a custom name (optional)" + placeholder={t('settings.tools.customNamePlaceholder')} />
{Object.keys(tool?.config).length !== 0 && tool.name !== 'api_tool' && (

- Authentication + {t('settings.tools.authentication')}

)}
@@ -218,7 +218,7 @@ export default function ToolConfig({

- Actions + {t('settings.tools.actions')}

{tool.name === 'api_tool' && (!tool.config.actions || @@ -227,7 +227,7 @@ export default function ToolConfig({ onClick={() => setActionModalState('ACTIVE')} className="rounded-full border border-solid border-violets-are-blue px-5 py-1 text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white" > - Add action + {t('settings.tools.addAction')} )}
@@ -244,7 +244,7 @@ export default function ToolConfig({ className="mx-auto mb-4 h-24 w-24" />

- No actions found + {t('settings.tools.noActionsFound')}

)} @@ -432,7 +432,7 @@ export default function ToolConfig({ className="mx-auto mb-4 h-24 w-24" />

- No actions found + {t('settings.tools.noActionsFound')}

)} @@ -445,15 +445,10 @@ export default function ToolConfig({ /> {showUnsavedModal && ( setShowUnsavedModal(state === 'ACTIVE')} - submitLabel={t('settings.tools.saveAndLeave', { - defaultValue: 'Save and Leave', - })} + submitLabel={t('settings.tools.saveAndLeave')} handleSubmit={() => { userService .updateTool( @@ -477,9 +472,7 @@ export default function ToolConfig({ handleGoBack(); }); }} - cancelLabel={t('settings.tools.leaveWithoutSaving', { - defaultValue: 'Leave without Saving', - })} + cancelLabel={t('settings.tools.leaveWithoutSaving')} handleCancel={() => { setShowUnsavedModal(false); handleGoBack(); @@ -597,36 +590,31 @@ function APIToolConfig({
-
- - URL - - { - setApiTool((prevApiTool) => { - const updatedActions = { - ...prevApiTool.config.actions, - }; - const updatedAction = { - ...updatedActions[actionName], - }; - updatedAction.url = e.target.value; - updatedActions[actionName] = updatedAction; - return { - ...prevApiTool, - config: { - ...prevApiTool.config, - actions: updatedActions, - }, - }; - }); - }} - borderVariant="thin" - placeholder="Enter url" - > -
+ { + setApiTool((prevApiTool) => { + const updatedActions = { + ...prevApiTool.config.actions, + }; + const updatedAction = { + ...updatedActions[actionName], + }; + updatedAction.url = e.target.value; + updatedActions[actionName] = updatedAction; + return { + ...prevApiTool, + config: { + ...prevApiTool.config, + actions: updatedActions, + }, + }; + }); + }} + borderVariant="thin" + placeholder={t('settings.tools.urlPlaceholder')} + />
@@ -666,36 +654,31 @@ function APIToolConfig({
-
- - Description - - { - setApiTool((prevApiTool) => { - const updatedActions = { - ...prevApiTool.config.actions, - }; - const updatedAction = { - ...updatedActions[actionName], - }; - updatedAction.description = e.target.value; - updatedActions[actionName] = updatedAction; - return { - ...prevApiTool, - config: { - ...prevApiTool.config, - actions: updatedActions, - }, - }; - }); - }} - borderVariant="thin" - placeholder="Enter description" - > -
+ { + setApiTool((prevApiTool) => { + const updatedActions = { + ...prevApiTool.config.actions, + }; + const updatedAction = { + ...updatedActions[actionName], + }; + updatedAction.description = e.target.value; + updatedActions[actionName] = updatedAction; + return { + ...prevApiTool, + config: { + ...prevApiTool.config, + actions: updatedActions, + }, + }; + }); + }} + borderVariant="thin" + placeholder={t('settings.tools.descriptionPlaceholder')} + />
void; }) { + const { t } = useTranslation(); + const [action, setAction] = React.useState(apiAction); const [newPropertyKey, setNewPropertyKey] = React.useState(''); const [addingPropertySection, setAddingPropertySection] = React.useState< @@ -1056,16 +1040,26 @@ function APIActionTable({

- Headers + {t('settings.tools.headers')}

- - - - - + + + + +
NameTypeFilled by LLMDescriptionValue + {t('settings.tools.name')} + + {t('settings.tools.type')} + + {t('settings.tools.filledByLLM')} + + {t('settings.tools.description')} + + {t('settings.tools.value')} +

- Query Parameters + {t('settings.tools.queryParameters')}

- - - - - + + + + +
NameTypeFilled by LLMDescriptionValue + {t('settings.tools.name')} + + {t('settings.tools.type')} + + {t('settings.tools.filledByLLM')} + + {t('settings.tools.description')} + + {t('settings.tools.value')} +

- Body + {t('settings.tools.body')}

- - - - - + + + + +
NameTypeFilled by LLMDescriptionValue + {t('settings.tools.name')} + + {t('settings.tools.type')} + + {t('settings.tools.filledByLLM')} + + {t('settings.tools.description')} + + {t('settings.tools.value')} + Date: Wed, 28 May 2025 03:29:48 +0530 Subject: [PATCH 3/7] (fix:menu) larger strings break --- frontend/src/components/ContextMenu.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ContextMenu.tsx b/frontend/src/components/ContextMenu.tsx index 762a7828..eef2217c 100644 --- a/frontend/src/components/ContextMenu.tsx +++ b/frontend/src/components/ContextMenu.tsx @@ -90,7 +90,7 @@ export default function ContextMenu({ onClick={(e) => e.stopPropagation()} >
{options.map((option, index) => ( @@ -109,7 +109,7 @@ export default function ContextMenu({ } `} > {option.icon && ( -
+
)} - {option.label} + {option.label} ))}
From 3e9155767b1d5eb13f1ff27a8d7c15bbda5cd5d8 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 29 May 2025 03:57:11 +0530 Subject: [PATCH 4/7] (fix:input) placeholder overflow --- frontend/src/components/Input.tsx | 6 +++++- frontend/src/settings/Documents.tsx | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/Input.tsx b/frontend/src/components/Input.tsx index a968511c..022c1632 100644 --- a/frontend/src/components/Input.tsx +++ b/frontend/src/components/Input.tsx @@ -60,7 +60,11 @@ const Input = ({ {placeholder && (
-

Back to all documents

+

{t('settings.documents.backToAll')}

-

{`${totalChunks} Chunks`}

+

{`${totalChunks} ${t('settings.documents.chunks')}`}

@@ -663,7 +663,7 @@ function DocumentChunks({ />
From 2ca9f708a653d4eab327cd5edd8ef1915616fefc Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 29 May 2025 04:00:25 +0530 Subject: [PATCH 6/7] (fix:menu) position smartly --- frontend/src/components/ContextMenu.tsx | 41 +++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ContextMenu.tsx b/frontend/src/components/ContextMenu.tsx index eef2217c..3713ffe6 100644 --- a/frontend/src/components/ContextMenu.tsx +++ b/frontend/src/components/ContextMenu.tsx @@ -30,7 +30,17 @@ export default function ContextMenu({ offset = { x: 0, y: 8 }, }: ContextMenuProps) { const menuRef = useRef(null); - + useEffect(() => { + if (isOpen && menuRef.current) { + const positionStyle = getMenuPosition(); + if (menuRef.current) { + Object.assign(menuRef.current.style, { + top: positionStyle.top, + left: positionStyle.left, + }); + } + } + }, [isOpen]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -61,20 +71,45 @@ export default function ContextMenu({ let top = rect.bottom + scrollY + offset.y; let left = rect.right + scrollX + offset.x; + // Get menu dimensions (need ref to be available) + const menuWidth = menuRef.current?.offsetWidth || 144; // Default min-width + const menuHeight = menuRef.current?.offsetHeight || 0; + + // Get viewport dimensions + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + // Adjust position based on specified position switch (position) { case 'bottom-left': left = rect.left + scrollX - offset.x; break; case 'top-right': - top = rect.top + scrollY - offset.y; + top = rect.top + scrollY - offset.y - menuHeight; break; case 'top-left': - top = rect.top + scrollY - offset.y; + top = rect.top + scrollY - offset.y - menuHeight; left = rect.left + scrollX - offset.x; break; // bottom-right is default } + if (left + menuWidth > viewportWidth) { + left = Math.max(5, viewportWidth - menuWidth - 5); + } + + if (left < 5) { + left = 5; + } + + if (top + menuHeight > viewportHeight + scrollY) { + top = rect.top + scrollY - menuHeight - offset.y; + } + + if (top < scrollY + 5) { + top = rect.bottom + scrollY + offset.y; + } + return { position: 'fixed', top: `${top}px`, From 8abc1de26d30ba7863c0e7e1860d059bde88be0f Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 29 May 2025 04:01:47 +0530 Subject: [PATCH 7/7] (feat:hooks) update useMediaQuery --- frontend/src/hooks/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index 2247cb07..bffcfb5c 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -35,21 +35,21 @@ export function useOutsideAlerter( export function useMediaQuery() { const mobileQuery = '(max-width: 768px)'; - const darkModeQuery = '(prefers-color-scheme: dark)'; // Detect dark mode - const desktopQuery = '(min-width: 960px)'; + const tabletQuery = '(max-width: 1024px)'; // Tablet breakpoint at 1024px + const desktopQuery = '(min-width: 1025px)'; // Desktop starts after tablet const [isMobile, setIsMobile] = useState(false); + const [isTablet, setIsTablet] = useState(false); const [isDesktop, setIsDesktop] = useState(false); - const [isDarkMode, setIsDarkMode] = useState(false); useEffect(() => { const mobileMedia = window.matchMedia(mobileQuery); + const tabletMedia = window.matchMedia(tabletQuery); const desktopMedia = window.matchMedia(desktopQuery); - const darkModeMedia = window.matchMedia(darkModeQuery); const updateMediaQueries = () => { setIsMobile(mobileMedia.matches); + setIsTablet(tabletMedia.matches && !mobileMedia.matches); // Tablet but not mobile setIsDesktop(desktopMedia.matches); - setIsDarkMode(darkModeMedia.matches); }; updateMediaQueries(); @@ -60,9 +60,9 @@ export function useMediaQuery() { return () => { window.removeEventListener('resize', listener); }; - }, [mobileQuery, desktopQuery, darkModeQuery]); + }, [mobileQuery, tabletQuery, desktopQuery]); - return { isMobile, isDesktop, isDarkMode }; + return { isMobile, isTablet, isDesktop }; } export function useDarkTheme() {