mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
feat: choose tool sticky
This commit is contained in:
parent
0f60fe7f2a
commit
bdb81fe20d
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue
Block a user