chore: placement menu leftpanel, and ux create add projects
This commit is contained in:
parent
311b79fe13
commit
b4df56e0d8
@ -1,4 +1,4 @@
|
|||||||
import { Link, useRouterState } from '@tanstack/react-router'
|
import { Link, useRouterState, useNavigate } from '@tanstack/react-router'
|
||||||
import { useLeftPanel } from '@/hooks/useLeftPanel'
|
import { useLeftPanel } from '@/hooks/useLeftPanel'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import {
|
import {
|
||||||
@ -58,6 +58,9 @@ const mainMenus = [
|
|||||||
route: route.project,
|
route: route.project,
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const secondaryMenus = [
|
||||||
{
|
{
|
||||||
title: 'common:assistants',
|
title: 'common:assistants',
|
||||||
icon: IconClipboardSmile,
|
icon: IconClipboardSmile,
|
||||||
@ -82,6 +85,7 @@ const LeftPanel = () => {
|
|||||||
const open = useLeftPanel((state) => state.open)
|
const open = useLeftPanel((state) => state.open)
|
||||||
const setLeftPanel = useLeftPanel((state) => state.setLeftPanel)
|
const setLeftPanel = useLeftPanel((state) => state.setLeftPanel)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const { isAuthenticated } = useAuth()
|
const { isAuthenticated } = useAuth()
|
||||||
|
|
||||||
@ -212,7 +216,12 @@ const LeftPanel = () => {
|
|||||||
if (editingProjectKey) {
|
if (editingProjectKey) {
|
||||||
updateFolder(editingProjectKey, name)
|
updateFolder(editingProjectKey, name)
|
||||||
} else {
|
} else {
|
||||||
addFolder(name)
|
const newProject = addFolder(name)
|
||||||
|
// Navigate to the newly created project
|
||||||
|
navigate({
|
||||||
|
to: '/project/$projectId',
|
||||||
|
params: { projectId: newProject.id },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setProjectDialogOpen(false)
|
setProjectDialogOpen(false)
|
||||||
setEditingProjectKey(null)
|
setEditingProjectKey(null)
|
||||||
@ -487,7 +496,7 @@ const LeftPanel = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col h-full overflow-y-scroll w-[calc(100%+6px)]">
|
<div className="flex flex-col h-full overflow-y-scroll w-[calc(100%+6px)]">
|
||||||
<div className="flex flex-col w-full h-full overflow-y-auto overflow-x-hidden">
|
<div className="flex flex-col w-full h-full overflow-y-auto overflow-x-hidden mb-3">
|
||||||
<div className="h-full w-full overflow-y-auto">
|
<div className="h-full w-full overflow-y-auto">
|
||||||
{favoritedThreads.length > 0 && (
|
{favoritedThreads.length > 0 && (
|
||||||
<>
|
<>
|
||||||
@ -607,6 +616,44 @@ const LeftPanel = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{secondaryMenus.map((menu) => {
|
||||||
|
if (!menu.isEnabled) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular menu items must have route and icon
|
||||||
|
if (!menu.route || !menu.icon) return null
|
||||||
|
|
||||||
|
const isActive = (() => {
|
||||||
|
// Settings routes
|
||||||
|
if (menu.route.includes(route.settings.index)) {
|
||||||
|
return currentPath.includes(route.settings.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default exact match for other routes
|
||||||
|
return currentPath === menu.route
|
||||||
|
})()
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={menu.title}
|
||||||
|
to={menu.route}
|
||||||
|
onClick={() => isSmallScreen && setLeftPanel(false)}
|
||||||
|
data-test-id={`menu-${menu.title}`}
|
||||||
|
activeOptions={{ exact: true }}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-1.5 cursor-pointer hover:bg-left-panel-fg/10 py-1 px-1 rounded',
|
||||||
|
isActive && 'bg-left-panel-fg/10'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<menu.icon size={18} className="text-left-panel-fg/70" />
|
||||||
|
<span className="font-medium text-left-panel-fg/90">
|
||||||
|
{t(menu.title)}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
{PlatformFeatures[PlatformFeature.AUTHENTICATION] && (
|
{PlatformFeatures[PlatformFeature.AUTHENTICATION] && (
|
||||||
<div className="space-y-1 shrink-0 py-1">
|
<div className="space-y-1 shrink-0 py-1">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -185,7 +185,10 @@ const SortableItem = memo(
|
|||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<IconDots
|
<IconDots
|
||||||
size={14}
|
size={14}
|
||||||
className="text-left-panel-fg/60 shrink-0 cursor-pointer px-0.5 -mr-1 data-[state=open]:bg-left-panel-fg/10 rounded group-hover/thread-list:data-[state=closed]:size-5 size-5 data-[state=closed]:size-0"
|
className={cn(
|
||||||
|
'text-left-panel-fg/60 shrink-0 cursor-pointer px-0.5 -mr-1 data-[state=open]:bg-left-panel-fg/10 rounded group-hover/thread-list:data-[state=closed]:size-5 size-5 data-[state=closed]:size-0',
|
||||||
|
variant === 'project' && 'text-main-view-fg/60'
|
||||||
|
)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|||||||
@ -13,7 +13,7 @@ type ThreadFolder = {
|
|||||||
type ThreadManagementState = {
|
type ThreadManagementState = {
|
||||||
folders: ThreadFolder[]
|
folders: ThreadFolder[]
|
||||||
setFolders: (folders: ThreadFolder[]) => void
|
setFolders: (folders: ThreadFolder[]) => void
|
||||||
addFolder: (name: string) => void
|
addFolder: (name: string) => ThreadFolder
|
||||||
updateFolder: (id: string, name: string) => void
|
updateFolder: (id: string, name: string) => void
|
||||||
deleteFolder: (id: string) => void
|
deleteFolder: (id: string) => void
|
||||||
getFolderById: (id: string) => ThreadFolder | undefined
|
getFolderById: (id: string) => ThreadFolder | undefined
|
||||||
@ -37,6 +37,7 @@ export const useThreadManagement = create<ThreadManagementState>()(
|
|||||||
set((state) => ({
|
set((state) => ({
|
||||||
folders: [...state.folders, newFolder],
|
folders: [...state.folders, newFolder],
|
||||||
}))
|
}))
|
||||||
|
return newFolder
|
||||||
},
|
},
|
||||||
|
|
||||||
updateFolder: (id, name) => {
|
updateFolder: (id, name) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute, useNavigate } from '@tanstack/react-router'
|
||||||
import { useState, useMemo } from 'react'
|
import { useState, useMemo } from 'react'
|
||||||
|
|
||||||
import { useThreadManagement } from '@/hooks/useThreadManagement'
|
import { useThreadManagement } from '@/hooks/useThreadManagement'
|
||||||
@ -31,6 +31,7 @@ function Project() {
|
|||||||
|
|
||||||
function ProjectContent() {
|
function ProjectContent() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const { folders, addFolder, updateFolder, deleteFolder, getFolderById } =
|
const { folders, addFolder, updateFolder, deleteFolder, getFolderById } =
|
||||||
useThreadManagement()
|
useThreadManagement()
|
||||||
const threads = useThreads((state) => state.threads)
|
const threads = useThreads((state) => state.threads)
|
||||||
@ -59,7 +60,12 @@ function ProjectContent() {
|
|||||||
if (editingKey) {
|
if (editingKey) {
|
||||||
updateFolder(editingKey, name)
|
updateFolder(editingKey, name)
|
||||||
} else {
|
} else {
|
||||||
addFolder(name)
|
const newProject = addFolder(name)
|
||||||
|
// Navigate to the newly created project
|
||||||
|
navigate({
|
||||||
|
to: '/project/$projectId',
|
||||||
|
params: { projectId: newProject.id },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
setEditingKey(null)
|
setEditingKey(null)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user