From 8ed68d9c1992b2b6d815f65dc23eef7617763f63 Mon Sep 17 00:00:00 2001 From: Roushan Singh Date: Fri, 3 Oct 2025 16:06:53 +0530 Subject: [PATCH 01/18] chore(ui): refine className for dropdown menu with animation states --- web-app/src/components/ui/dropdown-menu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-app/src/components/ui/dropdown-menu.tsx b/web-app/src/components/ui/dropdown-menu.tsx index 7a527aaca..e4782cf12 100644 --- a/web-app/src/components/ui/dropdown-menu.tsx +++ b/web-app/src/components/ui/dropdown-menu.tsx @@ -229,7 +229,7 @@ function DropdownMenuSubContent({ Date: Fri, 3 Oct 2025 16:14:27 +0530 Subject: [PATCH 02/18] chore: Reposition 'Remove project' option for better usability --- web-app/src/containers/ThreadList.tsx | 45 +++++++++++++-------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/web-app/src/containers/ThreadList.tsx b/web-app/src/containers/ThreadList.tsx index a8dadbb62..734aec710 100644 --- a/web-app/src/containers/ThreadList.tsx +++ b/web-app/src/containers/ThreadList.tsx @@ -262,32 +262,29 @@ const SortableItem = memo( )) )} - {thread.metadata?.project && ( - <> - - { - e.stopPropagation() - // Remove project from metadata - const projectName = thread.metadata?.project?.name - updateThread(thread.id, { - metadata: { - ...thread.metadata, - project: undefined, - }, - }) - toast.success( - `Thread removed from "${projectName}" successfully` - ) - }} - > - - Remove from project - - - )} + {thread.metadata?.project && ( + { + e.stopPropagation() + // Remove project from metadata + const projectName = thread.metadata?.project?.name + updateThread(thread.id, { + metadata: { + ...thread.metadata, + project: undefined, + }, + }) + toast.success( + `Thread removed from "${projectName}" successfully` + ) + }} + > + + Remove + + )} Date: Fri, 3 Oct 2025 16:20:51 +0530 Subject: [PATCH 03/18] feat: add project search and scrollable thread lists - Add search bar to filter projects by name in real-time - Implement scrollable thread container with max 4 visible threads - Add empty state for no search results - Add clear button (X) to reset search query --- web-app/src/locales/en/common.json | 5 ++- web-app/src/routes/project/index.tsx | 56 +++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/web-app/src/locales/en/common.json b/web-app/src/locales/en/common.json index 2eca7a699..690381188 100644 --- a/web-app/src/locales/en/common.json +++ b/web-app/src/locales/en/common.json @@ -284,7 +284,10 @@ "updated": "Updated:", "collapseThreads": "Collapse threads", "expandThreads": "Expand threads", - "update": "Update" + "update": "Update", + "searchProjects": "Search projects...", + "noProjectsFound": "No projects found", + "tryDifferentSearch": "Try a different search term" }, "toast": { "allThreadsUnfavorited": { diff --git a/web-app/src/routes/project/index.tsx b/web-app/src/routes/project/index.tsx index deb4cb2a6..5d3a30315 100644 --- a/web-app/src/routes/project/index.tsx +++ b/web-app/src/routes/project/index.tsx @@ -14,6 +14,8 @@ import { IconFolder, IconChevronDown, IconChevronRight, + IconSearch, + IconX, } from '@tabler/icons-react' import AddProjectDialog from '@/containers/dialogs/AddProjectDialog' import { DeleteProjectDialog } from '@/containers/dialogs/DeleteProjectDialog' @@ -42,6 +44,7 @@ function ProjectContent() { const [expandedProjects, setExpandedProjects] = useState>( new Set() ) + const [searchQuery, setSearchQuery] = useState('') const handleDelete = (id: string) => { setDeletingId(id) @@ -93,6 +96,16 @@ function ProjectContent() { }) } + // Filter projects based on search query + const filteredProjects = useMemo(() => { + if (!searchQuery.trim()) { + return folders + } + return folders.filter((folder) => + folder.name.toLowerCase().includes(searchQuery.toLowerCase()) + ) + }, [folders, searchQuery]) + return (
@@ -113,6 +126,33 @@ function ProjectContent() {
+ {/* Search Bar */} + {folders.length > 0 && ( +
+
+ + setSearchQuery(e.target.value)} + className="w-full pl-10 pr-4 py-2.5 bg-main-view-fg/5 border border-main-view-fg/10 rounded-lg text-main-view-fg placeholder:text-main-view-fg/50 focus:outline-none focus:ring-2 focus:ring-main-view-fg/20 focus:border-main-view-fg/20 transition-all" + /> + {searchQuery && ( + + )} +
+
+ )} + {folders.length === 0 ? (
@@ -123,9 +163,19 @@ function ProjectContent() { {t('projects.noProjectsYetDesc')}

+ ) : filteredProjects.length === 0 ? ( +
+ +

+ {t('projects.noProjectsFound')} +

+

+ {t('projects.tryDifferentSearch')} +

+
) : (
- {folders + {filteredProjects .slice() .sort((a, b) => b.updated_at - a.updated_at) .map((folder) => { @@ -218,7 +268,9 @@ function ProjectContent() { {/* Thread List */} {isExpanded && projectThreads.length > 0 && ( -
+
Date: Fri, 3 Oct 2025 16:42:10 +0530 Subject: [PATCH 04/18] (chore): rename translation keys to collapseProject/expandProject --- web-app/src/locales/de-DE/common.json | 8 ++++---- web-app/src/locales/en/common.json | 4 ++-- web-app/src/locales/id/common.json | 4 ++-- web-app/src/locales/pl/common.json | 4 ++-- web-app/src/locales/vn/common.json | 26 ++++++++++++++++++++++++++ web-app/src/locales/zh-CN/common.json | 26 ++++++++++++++++++++++++++ web-app/src/locales/zh-TW/common.json | 26 ++++++++++++++++++++++++++ web-app/src/routes/project/index.tsx | 4 ++-- 8 files changed, 90 insertions(+), 12 deletions(-) diff --git a/web-app/src/locales/de-DE/common.json b/web-app/src/locales/de-DE/common.json index 4ce743b46..65b7af707 100644 --- a/web-app/src/locales/de-DE/common.json +++ b/web-app/src/locales/de-DE/common.json @@ -272,8 +272,8 @@ "thread": "Thread", "threads": "Threads", "updated": "Aktualisiert:", - "collapseThreads": "Threads einklappen", - "expandThreads": "Threads ausklappen", + "collapseProject": "Projekt einklappen", + "expandProject": "Projekt ausklappen", "update": "Aktualisieren" }, "toast": { @@ -428,8 +428,8 @@ "thread": "Thread", "threads": "Threads", "updated": "Aktualisiert:", - "collapseThreads": "Threads einklappen", - "expandThreads": "Threads ausklappen", + "collapseProject": "Projekt einklappen", + "expandProject": "Projekt ausklappen", "update": "Aktualisieren" } } diff --git a/web-app/src/locales/en/common.json b/web-app/src/locales/en/common.json index 690381188..e39465545 100644 --- a/web-app/src/locales/en/common.json +++ b/web-app/src/locales/en/common.json @@ -282,8 +282,8 @@ "thread": "thread", "threads": "threads", "updated": "Updated:", - "collapseThreads": "Collapse threads", - "expandThreads": "Expand threads", + "collapseProject": "Collapse project", + "expandProject": "Expand project", "update": "Update", "searchProjects": "Search projects...", "noProjectsFound": "No projects found", diff --git a/web-app/src/locales/id/common.json b/web-app/src/locales/id/common.json index aa0c83fd9..3dbdfd90e 100644 --- a/web-app/src/locales/id/common.json +++ b/web-app/src/locales/id/common.json @@ -354,8 +354,8 @@ "thread": "utas", "threads": "utas", "updated": "Diperbarui:", - "collapseThreads": "Tutup utas", - "expandThreads": "Buka utas", + "collapseProject": "Tutup proyek", + "expandProject": "Buka proyek", "update": "Perbarui" } } diff --git a/web-app/src/locales/pl/common.json b/web-app/src/locales/pl/common.json index ca6f6b6b7..87e31117e 100644 --- a/web-app/src/locales/pl/common.json +++ b/web-app/src/locales/pl/common.json @@ -272,8 +272,8 @@ "thread": "wątek", "threads": "wątki", "updated": "Zaktualizowano:", - "collapseThreads": "Zwiń wątki", - "expandThreads": "Rozwiń wątki", + "collapseProject": "Zwiń projekt", + "expandProject": "Rozwiń projekt", "update": "Aktualizuj" }, "toast": { diff --git a/web-app/src/locales/vn/common.json b/web-app/src/locales/vn/common.json index 4c2d95101..92d4908a2 100644 --- a/web-app/src/locales/vn/common.json +++ b/web-app/src/locales/vn/common.json @@ -199,6 +199,32 @@ "title": "Cài đặt mô hình - {{modelId}}", "description": "Định cấu hình cài đặt mô hình để tối ưu hóa hiệu suất và hành vi." }, + "projects": { + "title": "Dự án", + "addProject": "Thêm dự án", + "editProject": "Chỉnh sửa dự án", + "deleteProject": "Xóa dự án", + "projectName": "Tên dự án", + "enterProjectName": "Nhập tên dự án", + "noProjectsYet": "Chưa có dự án nào", + "noProjectsYetDesc": "Tạo dự án đầu tiên của bạn để tổ chức các cuộc trò chuyện.", + "projectNotFound": "Không tìm thấy dự án", + "projectNotFoundDesc": "Dự án mà bạn đang tìm kiếm không tồn tại.", + "deleteProjectConfirm": "Bạn có chắc chắn muốn xóa dự án này không? Hành động này không thể hoàn tác.", + "noConversationsIn": "Chưa có cuộc trò chuyện nào trong {{projectName}}", + "startNewConversation": "Bắt đầu một cuộc trò chuyện mới với {{projectName}} bên dưới", + "conversationsIn": "Cuộc trò chuyện trong {{projectName}}", + "conversationsDescription": "Nhấp vào bất kỳ cuộc trò chuyện nào để tiếp tục trò chuyện hoặc bắt đầu một cuộc trò chuyện mới bên dưới.", + "thread": "chủ đề", + "threads": "chủ đề", + "updated": "Đã cập nhật:", + "collapseProject": "Thu gọn dự án", + "expandProject": "Mở rộng dự án", + "update": "Cập nhật", + "searchProjects": "Tìm kiếm dự án...", + "noProjectsFound": "Không tìm thấy dự án nào", + "tryDifferentSearch": "Thử từ khóa tìm kiếm khác" + }, "dialogs": { "changeDataFolder": { "title": "Thay đổi vị trí thư mục dữ liệu", diff --git a/web-app/src/locales/zh-CN/common.json b/web-app/src/locales/zh-CN/common.json index 6da4a83fa..05f7884a9 100644 --- a/web-app/src/locales/zh-CN/common.json +++ b/web-app/src/locales/zh-CN/common.json @@ -199,6 +199,32 @@ "title": "模型设置 - {{modelId}}", "description": "配置模型设置以优化性能和行为。" }, + "projects": { + "title": "项目", + "addProject": "添加项目", + "editProject": "编辑项目", + "deleteProject": "删除项目", + "projectName": "项目名称", + "enterProjectName": "输入项目名称", + "noProjectsYet": "还没有项目", + "noProjectsYetDesc": "创建您的第一个项目来组织对话。", + "projectNotFound": "未找到项目", + "projectNotFoundDesc": "您正在查找的项目不存在。", + "deleteProjectConfirm": "您确定要删除此项目吗?此操作无法撤销。", + "noConversationsIn": "{{projectName}} 中还没有对话", + "startNewConversation": "在下方开始与 {{projectName}} 的新对话", + "conversationsIn": "{{projectName}} 中的对话", + "conversationsDescription": "点击任何对话以继续聊天,或在下方开始新的对话。", + "thread": "线程", + "threads": "线程", + "updated": "已更新:", + "collapseProject": "收起项目", + "expandProject": "展开项目", + "update": "更新", + "searchProjects": "搜索项目...", + "noProjectsFound": "未找到项目", + "tryDifferentSearch": "尝试不同的搜索词" + }, "dialogs": { "changeDataFolder": { "title": "更改数据文件夹位置", diff --git a/web-app/src/locales/zh-TW/common.json b/web-app/src/locales/zh-TW/common.json index 4b9d1e7f6..d34858aa2 100644 --- a/web-app/src/locales/zh-TW/common.json +++ b/web-app/src/locales/zh-TW/common.json @@ -199,6 +199,32 @@ "title": "模型設定 - {{modelId}}", "description": "設定模型設定以最佳化效能和行為。" }, + "projects": { + "title": "專案", + "addProject": "新增專案", + "editProject": "編輯專案", + "deleteProject": "刪除專案", + "projectName": "專案名稱", + "enterProjectName": "輸入專案名稱", + "noProjectsYet": "尚無專案", + "noProjectsYetDesc": "建立您的第一個專案來組織對話。", + "projectNotFound": "找不到專案", + "projectNotFoundDesc": "您正在尋找的專案不存在。", + "deleteProjectConfirm": "您確定要刪除此專案嗎?此操作無法復原。", + "noConversationsIn": "{{projectName}} 中尚無對話", + "startNewConversation": "在下方開始與 {{projectName}} 的新對話", + "conversationsIn": "{{projectName}} 中的對話", + "conversationsDescription": "點擊任何對話以繼續聊天,或在下方開始新的對話。", + "thread": "執行緒", + "threads": "執行緒", + "updated": "已更新:", + "collapseProject": "收合專案", + "expandProject": "展開專案", + "update": "更新", + "searchProjects": "搜尋專案...", + "noProjectsFound": "找不到專案", + "tryDifferentSearch": "嘗試不同的搜尋詞" + }, "dialogs": { "changeDataFolder": { "title": "變更資料夾位置", diff --git a/web-app/src/routes/project/index.tsx b/web-app/src/routes/project/index.tsx index 5d3a30315..be3e20cf6 100644 --- a/web-app/src/routes/project/index.tsx +++ b/web-app/src/routes/project/index.tsx @@ -222,8 +222,8 @@ function ProjectContent() { className="size-8 cursor-pointer flex items-center justify-center rounded-md hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out mr-1" title={ isExpanded - ? t('projects.collapseThreads') - : t('projects.expandThreads') + ? t('projects.collapseProject') + : t('projects.expandProject') } onClick={() => toggleProjectExpansion(folder.id)} > From cc5130c1afd13789a555d236d3941da2850017da Mon Sep 17 00:00:00 2001 From: Roushan Singh Date: Fri, 3 Oct 2025 16:54:22 +0530 Subject: [PATCH 05/18] Fix Translation changes across locales --- web-app/src/containers/ThreadList.tsx | 6 ++-- web-app/src/locales/de-DE/common.json | 46 --------------------------- web-app/src/locales/vn/common.json | 3 ++ web-app/src/locales/zh-CN/common.json | 3 ++ web-app/src/locales/zh-TW/common.json | 3 ++ 5 files changed, 12 insertions(+), 49 deletions(-) diff --git a/web-app/src/containers/ThreadList.tsx b/web-app/src/containers/ThreadList.tsx index 734aec710..69bcc4d82 100644 --- a/web-app/src/containers/ThreadList.tsx +++ b/web-app/src/containers/ThreadList.tsx @@ -237,13 +237,13 @@ const SortableItem = memo( - Add to project + {t('common:projects.addToProject')} {availableProjects.length === 0 ? ( - No projects available + {t('common:projects.noProjectsAvailable')} ) : ( @@ -282,7 +282,7 @@ const SortableItem = memo( }} > - Remove + {t('common:projects.removeFromProject')} )} diff --git a/web-app/src/locales/de-DE/common.json b/web-app/src/locales/de-DE/common.json index 65b7af707..ad71eb789 100644 --- a/web-app/src/locales/de-DE/common.json +++ b/web-app/src/locales/de-DE/common.json @@ -385,51 +385,5 @@ "title": "Thread entfernt", "description": "Thread erfolgreich von \"{{projectName}}\" entfernt" } - }, - "projects": { - "title": "Projekte", - "addProject": "Projekt hinzufügen", - "addToProject": "Zu Projekt hinzufügen", - "removeFromProject": "Von Projekt entfernen", - "createNewProject": "Neues Projekt erstellen", - "editProject": "Projekt bearbeiten", - "deleteProject": "Projekt löschen", - "projectName": "Projektname", - "enterProjectName": "Projektname eingeben...", - "noProjectsAvailable": "Keine Projekte verfügbar", - "noProjectsYet": "Noch keine Projekte", - "noProjectsYetDesc": "Starten Sie ein neues Projekt, indem Sie auf die Schaltfläche Projekt hinzufügen klicken.", - "projectNotFound": "Projekt nicht gefunden", - "projectNotFoundDesc": "Das gesuchte Projekt existiert nicht oder wurde gelöscht.", - "deleteProjectDialog": { - "title": "Projekt löschen", - "description": "Sind Sie sicher, dass Sie dieses Projekt löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", - "deleteButton": "Löschen", - "successWithName": "Projekt \"{{projectName}}\" erfolgreich gelöscht", - "successWithoutName": "Projekt erfolgreich gelöscht", - "error": "Projekt konnte nicht gelöscht werden. Bitte versuchen Sie es erneut.", - "ariaLabel": "{{projectName}} löschen" - }, - "addProjectDialog": { - "createTitle": "Neues Projekt erstellen", - "editTitle": "Projekt bearbeiten", - "nameLabel": "Projektname", - "namePlaceholder": "Projektname eingeben...", - "createButton": "Erstellen", - "updateButton": "Aktualisieren", - "alreadyExists": "Projekt \"{{projectName}}\" existiert bereits", - "createSuccess": "Projekt \"{{projectName}}\" erfolgreich erstellt", - "renameSuccess": "Projekt von \"{{oldName}}\" zu \"{{newName}}\" umbenannt" - }, - "noConversationsIn": "Keine Gespräche in {{projectName}}", - "startNewConversation": "Starten Sie ein neues Gespräch mit {{projectName}} unten", - "conversationsIn": "Gespräche in {{projectName}}", - "conversationsDescription": "Klicken Sie auf ein Gespräch, um weiterzuchatten, oder starten Sie unten ein neues.", - "thread": "Thread", - "threads": "Threads", - "updated": "Aktualisiert:", - "collapseProject": "Projekt einklappen", - "expandProject": "Projekt ausklappen", - "update": "Aktualisieren" } } diff --git a/web-app/src/locales/vn/common.json b/web-app/src/locales/vn/common.json index 92d4908a2..28ddd29a7 100644 --- a/web-app/src/locales/vn/common.json +++ b/web-app/src/locales/vn/common.json @@ -211,6 +211,8 @@ "projectNotFound": "Không tìm thấy dự án", "projectNotFoundDesc": "Dự án mà bạn đang tìm kiếm không tồn tại.", "deleteProjectConfirm": "Bạn có chắc chắn muốn xóa dự án này không? Hành động này không thể hoàn tác.", + "addToProject": "Thêm vào dự án", + "removeFromProject": "Xóa khỏi dự án", "noConversationsIn": "Chưa có cuộc trò chuyện nào trong {{projectName}}", "startNewConversation": "Bắt đầu một cuộc trò chuyện mới với {{projectName}} bên dưới", "conversationsIn": "Cuộc trò chuyện trong {{projectName}}", @@ -221,6 +223,7 @@ "collapseProject": "Thu gọn dự án", "expandProject": "Mở rộng dự án", "update": "Cập nhật", + "noProjectsAvailable": "Không có dự án nào", "searchProjects": "Tìm kiếm dự án...", "noProjectsFound": "Không tìm thấy dự án nào", "tryDifferentSearch": "Thử từ khóa tìm kiếm khác" diff --git a/web-app/src/locales/zh-CN/common.json b/web-app/src/locales/zh-CN/common.json index 05f7884a9..69b15ac90 100644 --- a/web-app/src/locales/zh-CN/common.json +++ b/web-app/src/locales/zh-CN/common.json @@ -211,6 +211,8 @@ "projectNotFound": "未找到项目", "projectNotFoundDesc": "您正在查找的项目不存在。", "deleteProjectConfirm": "您确定要删除此项目吗?此操作无法撤销。", + "addToProject": "添加到项目", + "removeFromProject": "从项目中删除", "noConversationsIn": "{{projectName}} 中还没有对话", "startNewConversation": "在下方开始与 {{projectName}} 的新对话", "conversationsIn": "{{projectName}} 中的对话", @@ -221,6 +223,7 @@ "collapseProject": "收起项目", "expandProject": "展开项目", "update": "更新", + "noProjectsAvailable": "没有可用的项目", "searchProjects": "搜索项目...", "noProjectsFound": "未找到项目", "tryDifferentSearch": "尝试不同的搜索词" diff --git a/web-app/src/locales/zh-TW/common.json b/web-app/src/locales/zh-TW/common.json index d34858aa2..809ac0cd4 100644 --- a/web-app/src/locales/zh-TW/common.json +++ b/web-app/src/locales/zh-TW/common.json @@ -211,6 +211,8 @@ "projectNotFound": "找不到專案", "projectNotFoundDesc": "您正在尋找的專案不存在。", "deleteProjectConfirm": "您確定要刪除此專案嗎?此操作無法復原。", + "addToProject": "加入專案", + "removeFromProject": "從專案中移除", "noConversationsIn": "{{projectName}} 中尚無對話", "startNewConversation": "在下方開始與 {{projectName}} 的新對話", "conversationsIn": "{{projectName}} 中的對話", @@ -221,6 +223,7 @@ "collapseProject": "收合專案", "expandProject": "展開專案", "update": "更新", + "noProjectsAvailable": "沒有可用的專案", "searchProjects": "搜尋專案...", "noProjectsFound": "找不到專案", "tryDifferentSearch": "嘗試不同的搜尋詞" From 154bc177787f50ac31221f12267281b0c6694aa6 Mon Sep 17 00:00:00 2001 From: Roushan Singh Date: Fri, 3 Oct 2025 17:08:12 +0530 Subject: [PATCH 06/18] (chore): remove duplicate keys from de-DE/common.json --- web-app/src/locales/de-DE/common.json | 28 --------------------------- 1 file changed, 28 deletions(-) diff --git a/web-app/src/locales/de-DE/common.json b/web-app/src/locales/de-DE/common.json index ad71eb789..c2cf34164 100644 --- a/web-app/src/locales/de-DE/common.json +++ b/web-app/src/locales/de-DE/common.json @@ -356,34 +356,6 @@ "downloadAndVerificationComplete": { "title": "Download abgeschlossen", "description": "Modell \"{{item}}\" erfolgreich heruntergeladen und verifiziert" - }, - "projectCreated": { - "title": "Projekt erstellt", - "description": "Projekt \"{{projectName}}\" erfolgreich erstellt" - }, - "projectRenamed": { - "title": "Projekt umbenannt", - "description": "Projekt von \"{{oldName}}\" zu \"{{newName}}\" umbenannt" - }, - "projectDeleted": { - "title": "Projekt gelöscht", - "description": "Projekt \"{{projectName}}\" erfolgreich gelöscht" - }, - "projectAlreadyExists": { - "title": "Projekt existiert bereits", - "description": "Projekt \"{{projectName}}\" existiert bereits" - }, - "projectDeleteFailed": { - "title": "Löschen fehlgeschlagen", - "description": "Projekt konnte nicht gelöscht werden. Bitte versuchen Sie es erneut." - }, - "threadAssignedToProject": { - "title": "Thread zugewiesen", - "description": "Thread erfolgreich zu \"{{projectName}}\" hinzugefügt" - }, - "threadRemovedFromProject": { - "title": "Thread entfernt", - "description": "Thread erfolgreich von \"{{projectName}}\" entfernt" } } } From 291482cc166ee279dd8a5b6ff689a427473b089a Mon Sep 17 00:00:00 2001 From: Roushan Singh Date: Fri, 3 Oct 2025 17:17:10 +0530 Subject: [PATCH 07/18] Add SearchProjects to missing locales --- web-app/src/locales/de-DE/common.json | 5 ++++- web-app/src/locales/id/common.json | 5 ++++- web-app/src/locales/pl/common.json | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/web-app/src/locales/de-DE/common.json b/web-app/src/locales/de-DE/common.json index c2cf34164..699c15a08 100644 --- a/web-app/src/locales/de-DE/common.json +++ b/web-app/src/locales/de-DE/common.json @@ -274,7 +274,10 @@ "updated": "Aktualisiert:", "collapseProject": "Projekt einklappen", "expandProject": "Projekt ausklappen", - "update": "Aktualisieren" + "update": "Aktualisieren", + "searchProjects": "Projekte durchsuchen...", + "noProjectsFound": "Keine Projekte gefunden", + "tryDifferentSearch": "Versuchen Sie einen anderen Suchbegriff" }, "toast": { "allThreadsUnfavorited": { diff --git a/web-app/src/locales/id/common.json b/web-app/src/locales/id/common.json index 3dbdfd90e..77af93d31 100644 --- a/web-app/src/locales/id/common.json +++ b/web-app/src/locales/id/common.json @@ -356,6 +356,9 @@ "updated": "Diperbarui:", "collapseProject": "Tutup proyek", "expandProject": "Buka proyek", - "update": "Perbarui" + "update": "Perbarui", + "searchProjects": "Cari proyek...", + "noProjectsFound": "Tidak ada proyek ditemukan", + "tryDifferentSearch": "Coba kata kunci pencarian lain" } } diff --git a/web-app/src/locales/pl/common.json b/web-app/src/locales/pl/common.json index 87e31117e..ee25f6068 100644 --- a/web-app/src/locales/pl/common.json +++ b/web-app/src/locales/pl/common.json @@ -274,7 +274,10 @@ "updated": "Zaktualizowano:", "collapseProject": "Zwiń projekt", "expandProject": "Rozwiń projekt", - "update": "Aktualizuj" + "update": "Aktualizuj", + "searchProjects": "Szukaj projektów...", + "noProjectsFound": "Nie znaleziono projektów", + "tryDifferentSearch": "Spróbuj innego wyszukiwania" }, "toast": { "allThreadsUnfavorited": { From aa0c4b0d1b7676d8394bff95d0dc797de0f47c88 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Thu, 2 Oct 2025 12:32:52 +0700 Subject: [PATCH 08/18] fix: theme native system and check os support blur --- src-tauri/capabilities/log-app-window.json | 3 + src-tauri/capabilities/logs-window.json | 3 + .../capabilities/system-monitor-window.json | 16 ++- src-tauri/src/core/setup.rs | 31 +++++- src-tauri/src/core/system/commands.rs | 105 ++++++++++++++++++ src-tauri/src/lib.rs | 2 + src-tauri/tauri.conf.json | 2 +- web-app/index.html | 2 +- .../src/containers/ColorPickerAppBgColor.tsx | 26 +++-- web-app/src/containers/DropdownAssistant.tsx | 2 +- web-app/src/containers/LeftPanel.tsx | 3 +- .../src/hooks/__tests__/useAppearance.test.ts | 43 ++++++- web-app/src/hooks/useAppearance.ts | 68 +++++++++++- web-app/src/hooks/useTheme.ts | 4 +- web-app/src/index.css | 1 - web-app/src/providers/AppearanceProvider.tsx | 11 +- web-app/src/providers/ThemeProvider.tsx | 47 +++++++- web-app/src/routes/index.tsx | 13 ++- web-app/src/routes/logs.tsx | 21 ++-- web-app/src/services/app/default.ts | 5 + web-app/src/services/app/tauri.ts | 4 + web-app/src/services/app/types.ts | 1 + web-app/src/services/app/web.ts | 5 + web-app/src/services/theme/tauri.ts | 27 ++++- web-app/src/services/window/tauri.ts | 78 +++++++++++-- 25 files changed, 464 insertions(+), 59 deletions(-) diff --git a/src-tauri/capabilities/log-app-window.json b/src-tauri/capabilities/log-app-window.json index 9f95d1bb9..97dbf952d 100644 --- a/src-tauri/capabilities/log-app-window.json +++ b/src-tauri/capabilities/log-app-window.json @@ -3,10 +3,13 @@ "identifier": "logs-app-window", "description": "enables permissions for the logs app window", "windows": ["logs-app-window"], + "platforms": ["linux", "macOS", "windows"], "permissions": [ "core:default", "core:window:allow-start-dragging", "core:window:allow-set-theme", + "core:window:allow-get-all-windows", + "core:event:allow-listen", "log:default", "core:webview:allow-create-webview-window", "core:window:allow-set-focus" diff --git a/src-tauri/capabilities/logs-window.json b/src-tauri/capabilities/logs-window.json index ef56e6f75..34b1e033a 100644 --- a/src-tauri/capabilities/logs-window.json +++ b/src-tauri/capabilities/logs-window.json @@ -3,10 +3,13 @@ "identifier": "logs-window", "description": "enables permissions for the logs window", "windows": ["logs-window-local-api-server"], + "platforms": ["linux", "macOS", "windows"], "permissions": [ "core:default", "core:window:allow-start-dragging", "core:window:allow-set-theme", + "core:window:allow-get-all-windows", + "core:event:allow-listen", "log:default", "core:webview:allow-create-webview-window", "core:window:allow-set-focus" diff --git a/src-tauri/capabilities/system-monitor-window.json b/src-tauri/capabilities/system-monitor-window.json index 68a75e9fb..75a26fd87 100644 --- a/src-tauri/capabilities/system-monitor-window.json +++ b/src-tauri/capabilities/system-monitor-window.json @@ -8,6 +8,8 @@ "core:default", "core:window:allow-start-dragging", "core:window:allow-set-theme", + "core:window:allow-get-all-windows", + "core:event:allow-listen", "log:default", "core:webview:allow-create-webview-window", "core:window:allow-set-focus", @@ -15,6 +17,18 @@ "hardware:allow-get-system-usage", "llamacpp:allow-get-devices", "llamacpp:allow-read-gguf-metadata", - "deep-link:allow-get-current" + "deep-link:allow-get-current", + { + "identifier": "http:default", + "allow": [ + { + "url": "https://*:*" + }, + { + "url": "http://*:*" + } + ], + "deny": [] + } ] } diff --git a/src-tauri/src/core/setup.rs b/src-tauri/src/core/setup.rs index 6564d3609..7ba8f2f74 100644 --- a/src-tauri/src/core/setup.rs +++ b/src-tauri/src/core/setup.rs @@ -7,7 +7,7 @@ use std::{ }; use tar::Archive; use tauri::{ - App, Emitter, Manager, Runtime, Wry + App, Emitter, Manager, Runtime, Wry, WindowEvent }; #[cfg(desktop)] @@ -270,3 +270,32 @@ pub fn setup_tray(app: &App) -> tauri::Result { }) .build(app) } + +pub fn setup_theme_listener(app: &App) -> tauri::Result<()> { + // Setup theme listener for main window + if let Some(window) = app.get_webview_window("main") { + setup_window_theme_listener(app.handle().clone(), window); + } + + Ok(()) +} + +fn setup_window_theme_listener( + app_handle: tauri::AppHandle, + window: tauri::WebviewWindow, +) { + let window_label = window.label().to_string(); + let app_handle_clone = app_handle.clone(); + + window.on_window_event(move |event| { + if let WindowEvent::ThemeChanged(theme) = event { + let theme_str = match theme { + tauri::Theme::Light => "light", + tauri::Theme::Dark => "dark", + _ => "auto", + }; + log::info!("System theme changed to: {} for window: {}", theme_str, window_label); + let _ = app_handle_clone.emit("theme-changed", theme_str); + } + }); +} diff --git a/src-tauri/src/core/system/commands.rs b/src-tauri/src/core/system/commands.rs index 938e6f8bf..e01c36854 100644 --- a/src-tauri/src/core/system/commands.rs +++ b/src-tauri/src/core/system/commands.rs @@ -117,3 +117,108 @@ pub fn is_library_available(library: &str) -> bool { } } } + +// Check if the system supports blur/acrylic effects +// - Windows: Checks build version (17134+ for acrylic support) +// - Linux: Checks for KWin (KDE) or compositor with blur support +// - macOS: Always supported +#[tauri::command] +pub fn supports_blur_effects() -> bool { + #[cfg(target_os = "windows")] + { + // Windows 10 build 17134 (1803) and later support acrylic effects + // Windows 11 (build 22000+) has better support + use std::process::Command; + + if let Ok(output) = Command::new("cmd") + .args(&["/C", "ver"]) + .output() + { + if let Ok(version_str) = String::from_utf8(output.stdout) { + // Parse Windows version from output like "Microsoft Windows [Version 10.0.22631.4602]" + if let Some(version_part) = version_str.split("Version ").nth(1) { + if let Some(build_str) = version_part.split('.').nth(2) { + if let Ok(build) = build_str.split(']').next().unwrap_or("0").trim().parse::() { + // Windows 10 build 17134+ or Windows 11 build 22000+ support blur + let supports_blur = build >= 17134; + if supports_blur { + log::info!("✅ Windows build {} detected - Blur/Acrylic effects SUPPORTED", build); + } else { + log::warn!("❌ Windows build {} detected - Blur/Acrylic effects NOT SUPPORTED (requires build 17134+)", build); + } + return supports_blur; + } + } + } + } + } + + // If we can't detect version, assume it doesn't support blur for safety + log::warn!("❌ Could not detect Windows version - Assuming NO blur support for safety"); + false + } + + #[cfg(target_os = "linux")] + { + use std::process::Command; + + // Check for KDE Plasma with KWin (best blur support) + if let Ok(output) = Command::new("kwin_x11").arg("--version").output() { + if output.status.success() { + log::info!("✅ KDE/KWin detected - Blur effects SUPPORTED"); + return true; + } + } + + // Check for Wayland KWin + if let Ok(output) = Command::new("kwin_wayland").arg("--version").output() { + if output.status.success() { + log::info!("✅ KDE/KWin Wayland detected - Blur effects SUPPORTED"); + return true; + } + } + + // Check for GNOME with blur extensions (less reliable) + if std::env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().contains("GNOME") { + log::info!("🔍 GNOME detected - Blur support depends on extensions"); + // GNOME might have blur through extensions, allow it + return true; + } + + // Check for Compiz (older but has blur) + if let Ok(_) = Command::new("compiz").arg("--version").output() { + log::info!("✅ Compiz compositor detected - Blur effects SUPPORTED"); + return true; + } + + // Check for Picom with blur (common X11 compositor) + if let Ok(output) = Command::new("picom").arg("--version").output() { + if output.status.success() { + log::info!("✅ Picom compositor detected - Blur effects SUPPORTED"); + return true; + } + } + + // Check environment variable for compositor + if let Ok(compositor) = std::env::var("COMPOSITOR") { + log::info!("🔍 Compositor detected: {} - Assuming blur support", compositor); + return true; + } + + log::warn!("❌ No known blur-capable compositor detected on Linux"); + false + } + + #[cfg(target_os = "macos")] + { + // macOS always supports blur/vibrancy effects + log::info!("✅ macOS detected - Blur/Vibrancy effects SUPPORTED"); + true + } + + #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))] + { + log::warn!("❌ Unknown platform - Assuming NO blur support"); + false + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 628f22b08..85916f6cf 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -78,6 +78,7 @@ pub fn run() { core::system::commands::factory_reset, core::system::commands::read_logs, core::system::commands::is_library_available, + core::system::commands::supports_blur_effects, // Server commands core::server::commands::start_server, core::server::commands::stop_server, @@ -193,6 +194,7 @@ pub fn run() { } setup_mcp(app); + setup::setup_theme_listener(app)?; Ok(()) }) .build(tauri::generate_context!()) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index b0df3fc2f..fb1b1950b 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -40,7 +40,7 @@ } ], "security": { - "capabilities": ["default"], + "capabilities": ["default", "logs-app-window", "logs-window", "system-monitor-window"], "csp": { "default-src": "'self' customprotocol: asset: http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*", "connect-src": "ipc: http://ipc.localhost http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:* https: http:", diff --git a/web-app/index.html b/web-app/index.html index dd2e76ee6..55625d33c 100644 --- a/web-app/index.html +++ b/web-app/index.html @@ -17,7 +17,7 @@ Jan diff --git a/web-app/src/containers/ColorPickerAppBgColor.tsx b/web-app/src/containers/ColorPickerAppBgColor.tsx index 72e098aa4..36566d03b 100644 --- a/web-app/src/containers/ColorPickerAppBgColor.tsx +++ b/web-app/src/containers/ColorPickerAppBgColor.tsx @@ -1,4 +1,4 @@ -import { useAppearance, isDefaultColor } from '@/hooks/useAppearance' +import { useAppearance, isDefaultColor, useBlurSupport } from '@/hooks/useAppearance' import { cn } from '@/lib/utils' import { RgbaColor, RgbaColorPicker } from 'react-colorful' import { IconColorPicker } from '@tabler/icons-react' @@ -14,6 +14,12 @@ export function ColorPickerAppBgColor() { const { appBgColor, setAppBgColor } = useAppearance() const { isDark } = useTheme() const { t } = useTranslation() + const showAlphaSlider = useBlurSupport() + + // Helper to get alpha value based on blur support + const getAlpha = (defaultAlpha: number) => { + return showAlphaSlider ? defaultAlpha : 1 + } const predefineAppBgColor: RgbaColor[] = [ isDark @@ -21,38 +27,38 @@ export function ColorPickerAppBgColor() { r: 25, g: 25, b: 25, - a: IS_WINDOWS || IS_LINUX || !IS_TAURI ? 1 : 0.4, + a: getAlpha(0.4), } : { r: 255, g: 255, b: 255, - a: IS_WINDOWS || IS_LINUX || !IS_TAURI ? 1 : 0.4, + a: getAlpha(0.4), }, { r: 70, g: 79, b: 229, - a: IS_WINDOWS || IS_LINUX || !IS_TAURI ? 1 : 0.5, + a: getAlpha(0.5), }, { r: 238, g: 130, b: 238, - a: IS_WINDOWS || IS_LINUX || !IS_TAURI ? 1 : 0.5, + a: getAlpha(0.5), }, { r: 255, g: 99, b: 71, - a: IS_WINDOWS || IS_LINUX || !IS_TAURI ? 1 : 0.5, + a: getAlpha(0.5), }, { r: 255, g: 165, b: 0, - a: IS_WINDOWS || IS_LINUX || !IS_TAURI ? 1 : 0.5, + a: getAlpha(0.5), }, ] @@ -61,9 +67,9 @@ export function ColorPickerAppBgColor() { {predefineAppBgColor.map((item, i) => { const isSelected = (item.r === appBgColor.r && - item.g === appBgColor.g && - item.b === appBgColor.b && - item.a === appBgColor.a) || + item.g === appBgColor.g && + item.b === appBgColor.b && + item.a === appBgColor.a) || (isDefaultColor(appBgColor) && isDefaultColor(item)) return (
{ return ( <> -
+