feat: siderbar operation support portal (#1061)

This commit is contained in:
Joel
2023-08-31 17:46:51 +08:00
committed by GitHub
parent d75e8aeafa
commit 9458b8978f
13 changed files with 1964 additions and 1580 deletions

View File

@@ -1,19 +1,15 @@
'use client'
import type { FC } from 'react'
import React, { useRef, useState } from 'react'
import {
ChatBubbleOvalLeftEllipsisIcon,
} from '@heroicons/react/24/outline'
import { useBoolean, useInfiniteScroll } from 'ahooks'
import { ChatBubbleOvalLeftEllipsisIcon as ChatBubbleOvalLeftEllipsisSolidIcon } from '@heroicons/react/24/solid'
import cn from 'classnames'
import { useTranslation } from 'react-i18next'
import RenameModal from '../rename-modal'
import s from './style.module.css'
import Item from './item'
import type { ConversationItem } from '@/models/share'
import { fetchConversations, renameConversation } from '@/service/share'
import { fetchConversations as fetchUniversalConversations, renameConversation as renameUniversalConversation } from '@/service/universal-chat'
import ItemOperation from '@/app/components/explore/item-operation'
import Toast from '@/app/components/base/toast'
export type IListProps = {
@@ -52,7 +48,6 @@ const List: FC<IListProps> = ({
onDelete,
}) => {
const { t } = useTranslation()
const listRef = useRef<HTMLDivElement>(null)
useInfiniteScroll(
@@ -130,45 +125,17 @@ const List: FC<IListProps> = ({
>
{list.map((item) => {
const isCurrent = item.id === currentId
const ItemIcon
= isCurrent ? ChatBubbleOvalLeftEllipsisSolidIcon : ChatBubbleOvalLeftEllipsisIcon
return (
<div
onClick={() => onCurrentIdChange(item.id)}
<Item
key={item.id}
className={cn(s.item,
isCurrent
? 'bg-primary-50 text-primary-600'
: 'text-gray-700 hover:bg-gray-200 hover:text-gray-700',
'group flex justify-between items-center rounded-md px-2 py-2 text-sm font-medium cursor-pointer',
)}
>
<div className='flex items-center w-0 grow'>
<ItemIcon
className={cn(
isCurrent
? 'text-primary-600'
: 'text-gray-400 group-hover:text-gray-500',
'mr-3 h-5 w-5 flex-shrink-0',
)}
aria-hidden="true"
/>
<span>{item.name}</span>
</div>
{item.id !== '-1' && (
<div className={cn(s.opBtn, 'shrink-0')} onClick={e => e.stopPropagation()}>
<ItemOperation
isPinned={isPinned}
togglePin={() => onPinChanged(item.id)}
isShowRenameConversation
onRenameConversation={() => showRename(item)}
isShowDelete
onDelete={() => onDelete(item.id)}
/>
</div>
)}
</div>
item={item}
isCurrent={isCurrent}
onClick={onCurrentIdChange}
isPinned={isPinned}
togglePin={onPinChanged}
onDelete={onDelete}
onRenameConversation={showRename}
/>
)
})}
{isShowRename && (

View File

@@ -0,0 +1,77 @@
'use client'
import type { FC } from 'react'
import React, { useRef } from 'react'
import cn from 'classnames'
import { ChatBubbleOvalLeftEllipsisIcon as ChatBubbleOvalLeftEllipsisSolidIcon } from '@heroicons/react/24/solid'
import {
ChatBubbleOvalLeftEllipsisIcon,
} from '@heroicons/react/24/outline'
import { useHover } from 'ahooks'
import ItemOperation from '@/app/components/explore/item-operation'
import type { ConversationItem } from '@/models/share'
export type IItemProps = {
onClick: (id: string) => void
item: ConversationItem
isCurrent: boolean
isPinned: boolean
togglePin: (id: string) => void
onDelete: (id: string) => void
onRenameConversation: (item: ConversationItem) => void
}
const Item: FC<IItemProps> = ({
isCurrent,
item,
onClick,
isPinned,
togglePin,
onDelete,
onRenameConversation,
}) => {
const ItemIcon = isCurrent ? ChatBubbleOvalLeftEllipsisSolidIcon : ChatBubbleOvalLeftEllipsisIcon
const ref = useRef(null)
const isHovering = useHover(ref)
return (
<div
ref={ref}
onClick={() => onClick(item.id)}
key={item.id}
className={cn(
isCurrent
? 'bg-primary-50 text-primary-600'
: 'text-gray-700 hover:bg-gray-200 hover:text-gray-700',
'group flex justify-between items-center rounded-md px-2 py-2 text-sm font-medium cursor-pointer',
)}
>
<div className='flex items-center w-0 grow'>
<ItemIcon
className={cn(
isCurrent
? 'text-primary-600'
: 'text-gray-400 group-hover:text-gray-500',
'mr-3 h-5 w-5 flex-shrink-0',
)}
aria-hidden="true"
/>
<span>{item.name}</span>
</div>
{item.id !== '-1' && (
<div className='shrink-0 h-6' onClick={e => e.stopPropagation()}>
<ItemOperation
isPinned={isPinned}
isItemHovering={isHovering}
togglePin={() => togglePin(item.id)}
isShowDelete
isShowRenameConversation
onRenameConversation={() => onRenameConversation(item)}
onDelete={() => onDelete(item.id)}
/>
</div>
)}
</div>
)
}
export default React.memo(Item)

View File

@@ -1,7 +0,0 @@
.opBtn {
visibility: hidden;
}
.item:hover .opBtn {
visibility: visible;
}