feat: choose tool sticky

This commit is contained in:
Joel 2024-10-18 18:18:42 +08:00
parent 0f60fe7f2a
commit bdb81fe20d
4 changed files with 98 additions and 18 deletions

View File

@ -1,5 +1,6 @@
import {
useMemo,
useRef,
useState,
} from 'react'
import type {
@ -51,6 +52,10 @@ const AllTools = ({
})
})
}, [activeTab, buildInTools, customTools, workflowTools, searchText, language])
const pluginRef = useRef(null)
const wrapElemRef = useRef<HTMLDivElement>(null)
return (
<div>
<div className='flex items-center justify-between px-3 bg-background-default-hover border-b-[0.5px] border-black/[0.08] shadow-xs'>
@ -73,13 +78,19 @@ const AllTools = ({
</div>
<ViewTypeSelect viewType={activeView} onChange={setActiveView} />
</div>
<PluginList list={[toolNotion, extensionDallE, modelGPT4] as any} />
<Tools
showWorkflowEmpty={activeTab === ToolTypeEnum.Workflow}
tools={tools}
onSelect={onSelect}
viewType={activeView}
/>
<div
ref={wrapElemRef}
className='max-h-[464px] overflow-y-auto'
onScroll={(pluginRef.current as any)?.handleScroll}
>
<Tools
showWorkflowEmpty={activeTab === ToolTypeEnum.Workflow}
tools={tools}
onSelect={onSelect}
viewType={activeView}
/>
<PluginList wrapElemRef={wrapElemRef} list={[toolNotion, extensionDallE, modelGPT4] as any} ref={pluginRef} />
</div>
</div>
)
}

View File

@ -1,26 +1,50 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll'
import Item from './item'
import type { Plugin } from '@/app/components/plugins/types.ts'
import cn from '@/utils/classnames'
type Props = {
wrapElemRef: React.RefObject<HTMLElement>
list: Plugin[]
// onInstall: () =>
}
const List: FC<Props> = ({
const List = ({
wrapElemRef,
list,
}) => {
}: Props, ref: any) => {
const { t } = useTranslation()
const nextToStickyELemRef = useRef<HTMLDivElement>(null)
const { handleScroll, scrollPosition } = useStickyScroll({
wrapElemRef,
nextToStickyELemRef,
})
const stickyClassName = useMemo(() => {
switch (scrollPosition) {
case ScrollPosition.aboveTheWrap:
return 'top-0 shadow-md bg-white'
case ScrollPosition.showing:
return 'bottom-0'
case ScrollPosition.belowTheWrap:
return 'bottom-0 border-t border-gray-500 bg-white text-blue-500'
}
}, [scrollPosition])
useImperativeHandle(ref, () => ({
handleScroll,
}))
return (
<div>
<div className='pt-3 px-4 py-1 text-text-primary system-sm-medium'>
<>
<div
className={cn('sticky z-10 pt-3 px-4 py-1 text-text-primary system-sm-medium', stickyClassName)}>
{t('plugin.fromMarketplace')}
</div>
<div className='p-1'>
<div className='p-1 pb-[500px]' ref={nextToStickyELemRef}>
{list.map((item, index) => (
<Item
key={index}
@ -29,7 +53,7 @@ const List: FC<Props> = ({
/>
))}
</div>
</div>
</>
)
}
export default React.memo(List)
export default forwardRef(List)

View File

@ -75,7 +75,7 @@ const Blocks = ({
}
return (
<div className='p-1 max-w-[320px] max-h-[464px] overflow-y-auto'>
<div className='p-1 max-w-[320px]'>
{
!tools.length && !showWorkflowEmpty && (
<div className='flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'>{t('workflow.tabs.noResult')}</div>

View File

@ -0,0 +1,45 @@
import React from 'react'
import { useThrottleFn } from 'ahooks'
export enum ScrollPosition {
belowTheWrap = 'belowTheWrap',
showing = 'showing',
aboveTheWrap = 'aboveTheWrap',
}
type Params = {
wrapElemRef: React.RefObject<HTMLElement>
nextToStickyELemRef: React.RefObject<HTMLElement>
}
const useStickyScroll = ({
wrapElemRef,
nextToStickyELemRef,
}: Params) => {
const [scrollPosition, setScrollPosition] = React.useState<ScrollPosition>(ScrollPosition.belowTheWrap)
const { run: handleScroll } = useThrottleFn(() => {
const wrapDom = wrapElemRef.current
const stickyDOM = nextToStickyELemRef.current
if (!wrapDom || !stickyDOM)
return
const { height: wrapHeight, top: wrapTop } = wrapDom.getBoundingClientRect()
const { top: nextToStickyTop } = stickyDOM.getBoundingClientRect()
let scrollPositionNew = ScrollPosition.belowTheWrap
if (nextToStickyTop - wrapTop >= wrapHeight)
scrollPositionNew = ScrollPosition.belowTheWrap
else if (nextToStickyTop <= wrapTop)
scrollPositionNew = ScrollPosition.aboveTheWrap
else
scrollPositionNew = ScrollPosition.showing
if (scrollPosition !== scrollPositionNew)
setScrollPosition(scrollPositionNew)
}, { wait: 100 })
return {
handleScroll,
scrollPosition,
}
}
export default useStickyScroll