Merge pull request #6726 from github-roushan/dropdown-ui
UI enhancement for projects
This commit is contained in:
commit
80ee8fd2b2
@ -229,7 +229,7 @@ function DropdownMenuSubContent({
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
data-slot="dropdown-menu-sub-content"
|
||||
className={cn(
|
||||
'bg-main-view text-main-view-fg border-main-view-fg/5 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[51] min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
||||
'bg-main-view text-main-view-fg border-main-view-fg/5 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[51] min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-y-auto max-h-[var(--radix-dropdown-menu-content-available-height)] rounded-md border p-1 shadow-lg',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@ -237,13 +237,13 @@ const SortableItem = memo(
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="gap-2">
|
||||
<IconFolder size={16} />
|
||||
<span>Add to project</span>
|
||||
<span>{t('common:projects.addToProject')}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
{availableProjects.length === 0 ? (
|
||||
<DropdownMenuItem disabled>
|
||||
<span className="text-left-panel-fg/50">
|
||||
No projects available
|
||||
{t('common:projects.noProjectsAvailable')}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
@ -262,9 +262,9 @@ const SortableItem = memo(
|
||||
</DropdownMenuItem>
|
||||
))
|
||||
)}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
{thread.metadata?.project && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
@ -282,12 +282,9 @@ const SortableItem = memo(
|
||||
}}
|
||||
>
|
||||
<IconX size={16} />
|
||||
<span>Remove from project</span>
|
||||
<span>{t('common:projects.removeFromProject')}</span>
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DeleteThreadDialog
|
||||
thread={thread}
|
||||
|
||||
@ -272,9 +272,12 @@
|
||||
"thread": "Thread",
|
||||
"threads": "Threads",
|
||||
"updated": "Aktualisiert:",
|
||||
"collapseThreads": "Threads einklappen",
|
||||
"expandThreads": "Threads ausklappen",
|
||||
"update": "Aktualisieren"
|
||||
"collapseProject": "Projekt einklappen",
|
||||
"expandProject": "Projekt ausklappen",
|
||||
"update": "Aktualisieren",
|
||||
"searchProjects": "Projekte durchsuchen...",
|
||||
"noProjectsFound": "Keine Projekte gefunden",
|
||||
"tryDifferentSearch": "Versuchen Sie einen anderen Suchbegriff"
|
||||
},
|
||||
"toast": {
|
||||
"allThreadsUnfavorited": {
|
||||
@ -356,80 +359,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"
|
||||
}
|
||||
},
|
||||
"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:",
|
||||
"collapseThreads": "Threads einklappen",
|
||||
"expandThreads": "Threads ausklappen",
|
||||
"update": "Aktualisieren"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,9 +282,12 @@
|
||||
"thread": "thread",
|
||||
"threads": "threads",
|
||||
"updated": "Updated:",
|
||||
"collapseThreads": "Collapse threads",
|
||||
"expandThreads": "Expand threads",
|
||||
"update": "Update"
|
||||
"collapseProject": "Collapse project",
|
||||
"expandProject": "Expand project",
|
||||
"update": "Update",
|
||||
"searchProjects": "Search projects...",
|
||||
"noProjectsFound": "No projects found",
|
||||
"tryDifferentSearch": "Try a different search term"
|
||||
},
|
||||
"toast": {
|
||||
"allThreadsUnfavorited": {
|
||||
|
||||
@ -354,8 +354,11 @@
|
||||
"thread": "utas",
|
||||
"threads": "utas",
|
||||
"updated": "Diperbarui:",
|
||||
"collapseThreads": "Tutup utas",
|
||||
"expandThreads": "Buka utas",
|
||||
"update": "Perbarui"
|
||||
"collapseProject": "Tutup proyek",
|
||||
"expandProject": "Buka proyek",
|
||||
"update": "Perbarui",
|
||||
"searchProjects": "Cari proyek...",
|
||||
"noProjectsFound": "Tidak ada proyek ditemukan",
|
||||
"tryDifferentSearch": "Coba kata kunci pencarian lain"
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,9 +272,12 @@
|
||||
"thread": "wątek",
|
||||
"threads": "wątki",
|
||||
"updated": "Zaktualizowano:",
|
||||
"collapseThreads": "Zwiń wątki",
|
||||
"expandThreads": "Rozwiń wątki",
|
||||
"update": "Aktualizuj"
|
||||
"collapseProject": "Zwiń projekt",
|
||||
"expandProject": "Rozwiń projekt",
|
||||
"update": "Aktualizuj",
|
||||
"searchProjects": "Szukaj projektów...",
|
||||
"noProjectsFound": "Nie znaleziono projektów",
|
||||
"tryDifferentSearch": "Spróbuj innego wyszukiwania"
|
||||
},
|
||||
"toast": {
|
||||
"allThreadsUnfavorited": {
|
||||
|
||||
@ -199,6 +199,35 @@
|
||||
"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.",
|
||||
"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}}",
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
"dialogs": {
|
||||
"changeDataFolder": {
|
||||
"title": "Thay đổi vị trí thư mục dữ liệu",
|
||||
|
||||
@ -199,6 +199,35 @@
|
||||
"title": "模型设置 - {{modelId}}",
|
||||
"description": "配置模型设置以优化性能和行为。"
|
||||
},
|
||||
"projects": {
|
||||
"title": "项目",
|
||||
"addProject": "添加项目",
|
||||
"editProject": "编辑项目",
|
||||
"deleteProject": "删除项目",
|
||||
"projectName": "项目名称",
|
||||
"enterProjectName": "输入项目名称",
|
||||
"noProjectsYet": "还没有项目",
|
||||
"noProjectsYetDesc": "创建您的第一个项目来组织对话。",
|
||||
"projectNotFound": "未找到项目",
|
||||
"projectNotFoundDesc": "您正在查找的项目不存在。",
|
||||
"deleteProjectConfirm": "您确定要删除此项目吗?此操作无法撤销。",
|
||||
"addToProject": "添加到项目",
|
||||
"removeFromProject": "从项目中删除",
|
||||
"noConversationsIn": "{{projectName}} 中还没有对话",
|
||||
"startNewConversation": "在下方开始与 {{projectName}} 的新对话",
|
||||
"conversationsIn": "{{projectName}} 中的对话",
|
||||
"conversationsDescription": "点击任何对话以继续聊天,或在下方开始新的对话。",
|
||||
"thread": "线程",
|
||||
"threads": "线程",
|
||||
"updated": "已更新:",
|
||||
"collapseProject": "收起项目",
|
||||
"expandProject": "展开项目",
|
||||
"update": "更新",
|
||||
"noProjectsAvailable": "没有可用的项目",
|
||||
"searchProjects": "搜索项目...",
|
||||
"noProjectsFound": "未找到项目",
|
||||
"tryDifferentSearch": "尝试不同的搜索词"
|
||||
},
|
||||
"dialogs": {
|
||||
"changeDataFolder": {
|
||||
"title": "更改数据文件夹位置",
|
||||
|
||||
@ -199,6 +199,35 @@
|
||||
"title": "模型設定 - {{modelId}}",
|
||||
"description": "設定模型設定以最佳化效能和行為。"
|
||||
},
|
||||
"projects": {
|
||||
"title": "專案",
|
||||
"addProject": "新增專案",
|
||||
"editProject": "編輯專案",
|
||||
"deleteProject": "刪除專案",
|
||||
"projectName": "專案名稱",
|
||||
"enterProjectName": "輸入專案名稱",
|
||||
"noProjectsYet": "尚無專案",
|
||||
"noProjectsYetDesc": "建立您的第一個專案來組織對話。",
|
||||
"projectNotFound": "找不到專案",
|
||||
"projectNotFoundDesc": "您正在尋找的專案不存在。",
|
||||
"deleteProjectConfirm": "您確定要刪除此專案嗎?此操作無法復原。",
|
||||
"addToProject": "加入專案",
|
||||
"removeFromProject": "從專案中移除",
|
||||
"noConversationsIn": "{{projectName}} 中尚無對話",
|
||||
"startNewConversation": "在下方開始與 {{projectName}} 的新對話",
|
||||
"conversationsIn": "{{projectName}} 中的對話",
|
||||
"conversationsDescription": "點擊任何對話以繼續聊天,或在下方開始新的對話。",
|
||||
"thread": "執行緒",
|
||||
"threads": "執行緒",
|
||||
"updated": "已更新:",
|
||||
"collapseProject": "收合專案",
|
||||
"expandProject": "展開專案",
|
||||
"update": "更新",
|
||||
"noProjectsAvailable": "沒有可用的專案",
|
||||
"searchProjects": "搜尋專案...",
|
||||
"noProjectsFound": "找不到專案",
|
||||
"tryDifferentSearch": "嘗試不同的搜尋詞"
|
||||
},
|
||||
"dialogs": {
|
||||
"changeDataFolder": {
|
||||
"title": "變更資料夾位置",
|
||||
|
||||
@ -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<Set<string>>(
|
||||
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 (
|
||||
<div className="flex h-full flex-col justify-center">
|
||||
<HeaderPage>
|
||||
@ -113,6 +126,33 @@ function ProjectContent() {
|
||||
</HeaderPage>
|
||||
<div className="h-full overflow-y-auto flex flex-col">
|
||||
<div className="p-4 w-full md:w-3/4 mx-auto mt-2">
|
||||
{/* Search Bar */}
|
||||
{folders.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<div className="relative">
|
||||
<IconSearch
|
||||
size={18}
|
||||
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-main-view-fg/50"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('projects.searchProjects')}
|
||||
value={searchQuery}
|
||||
onChange={(e) => 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 && (
|
||||
<button
|
||||
onClick={() => setSearchQuery('')}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-main-view-fg/50 hover:text-main-view-fg transition-colors"
|
||||
>
|
||||
<IconX size={18} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{folders.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<IconFolder size={48} className="text-main-view-fg/30 mb-4" />
|
||||
@ -123,9 +163,19 @@ function ProjectContent() {
|
||||
{t('projects.noProjectsYetDesc')}
|
||||
</p>
|
||||
</div>
|
||||
) : filteredProjects.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<IconSearch size={48} className="text-main-view-fg/30 mb-4" />
|
||||
<h3 className="text-lg font-medium text-main-view-fg/60 mb-2">
|
||||
{t('projects.noProjectsFound')}
|
||||
</h3>
|
||||
<p className="text-main-view-fg/50 text-sm">
|
||||
{t('projects.tryDifferentSearch')}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{folders
|
||||
{filteredProjects
|
||||
.slice()
|
||||
.sort((a, b) => b.updated_at - a.updated_at)
|
||||
.map((folder) => {
|
||||
@ -172,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)}
|
||||
>
|
||||
@ -218,7 +268,9 @@ function ProjectContent() {
|
||||
|
||||
{/* Thread List */}
|
||||
{isExpanded && projectThreads.length > 0 && (
|
||||
<div className="mt-3 pl-2">
|
||||
<div
|
||||
className="mt-3 pl-2 pr-2 max-h-[190px] overflow-y-auto overflow-x-hidden [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-main-view-fg/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-main-view-fg/30"
|
||||
>
|
||||
<ThreadList
|
||||
threads={projectThreads}
|
||||
variant="project"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user