marketplace
parent
060a894bd1
commit
c1e0a939b0
@ -0,0 +1,41 @@
|
||||
'use client'
|
||||
|
||||
import type { ReactNode } from 'react'
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
createContext,
|
||||
useContextSelector,
|
||||
} from 'use-context-selector'
|
||||
|
||||
export type MarketplaceContextValue = {
|
||||
scrollIntersected: boolean
|
||||
setScrollIntersected: (scrollIntersected: boolean) => void
|
||||
}
|
||||
|
||||
export const MarketplaceContext = createContext<MarketplaceContextValue>({
|
||||
scrollIntersected: false,
|
||||
setScrollIntersected: () => {},
|
||||
})
|
||||
|
||||
type MarketplaceContextProviderProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) {
|
||||
return useContextSelector(MarketplaceContext, selector)
|
||||
}
|
||||
|
||||
export const MarketplaceContextProvider = ({
|
||||
children,
|
||||
}: MarketplaceContextProviderProps) => {
|
||||
const [scrollIntersected, setScrollIntersected] = useState(false)
|
||||
|
||||
return (
|
||||
<MarketplaceContext.Provider value={{
|
||||
scrollIntersected,
|
||||
setScrollIntersected,
|
||||
}}>
|
||||
{children}
|
||||
</MarketplaceContext.Provider>
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
'use client'
|
||||
|
||||
import type { ReactNode } from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type HeaderWrapperProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
const HeaderWrapper = ({
|
||||
children,
|
||||
}: HeaderWrapperProps) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'py-10',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeaderWrapper
|
||||
@ -0,0 +1,39 @@
|
||||
import SearchBox from './search-box'
|
||||
import PluginTypeSwitch from './plugin-type-switch'
|
||||
import IntersectionLine from './intersection-line'
|
||||
|
||||
const Header = () => {
|
||||
return (
|
||||
<>
|
||||
<h1 className='mb-2 text-center title-4xl-semi-bold text-text-primary'>
|
||||
Empower your AI development
|
||||
</h1>
|
||||
<h2 className='flex justify-center items-center mb-4 text-center body-md-regular text-text-tertiary'>
|
||||
Discover
|
||||
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||
models
|
||||
</span>
|
||||
,
|
||||
<span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||
tools
|
||||
</span>
|
||||
,
|
||||
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||
extensions
|
||||
</span>
|
||||
and
|
||||
<span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
|
||||
bundles
|
||||
</span>
|
||||
in Dify Marketplace
|
||||
</h2>
|
||||
<IntersectionLine />
|
||||
<div className='flex items-center justify-center mb-[15px]'>
|
||||
<SearchBox />
|
||||
</div>
|
||||
<PluginTypeSwitch />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header
|
||||
@ -1,20 +0,0 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export const useScrollIntersection = (
|
||||
rootRef: React.RefObject<HTMLDivElement>,
|
||||
anchorRef: React.RefObject<HTMLDivElement>,
|
||||
callback: (isIntersecting: boolean) => void,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
let observer: IntersectionObserver | undefined
|
||||
if (rootRef.current && anchorRef.current) {
|
||||
observer = new IntersectionObserver((entries) => {
|
||||
callback(entries[0].isIntersecting)
|
||||
}, {
|
||||
root: rootRef.current,
|
||||
})
|
||||
observer.observe(anchorRef.current)
|
||||
}
|
||||
return () => observer?.disconnect()
|
||||
}, [rootRef, anchorRef, callback])
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import { PluginPageContext } from '../../plugin-page/context'
|
||||
import { MarketplaceContext } from '../context'
|
||||
|
||||
export const useScrollIntersection = (
|
||||
anchorRef: React.RefObject<HTMLDivElement>,
|
||||
) => {
|
||||
const containerRef = useContextSelector(PluginPageContext, v => v.containerRef)
|
||||
const scrollIntersected = useContextSelector(MarketplaceContext, v => v.scrollIntersected)
|
||||
const setScrollIntersected = useContextSelector(MarketplaceContext, v => v.setScrollIntersected)
|
||||
|
||||
useEffect(() => {
|
||||
let observer: IntersectionObserver | undefined
|
||||
if (containerRef.current && anchorRef.current) {
|
||||
observer = new IntersectionObserver((entries) => {
|
||||
console.log(entries, 'entries')
|
||||
if (entries[0].isIntersecting && !scrollIntersected)
|
||||
setScrollIntersected(true)
|
||||
|
||||
if (!entries[0].isIntersecting && scrollIntersected)
|
||||
setScrollIntersected(false)
|
||||
}, {
|
||||
root: containerRef.current,
|
||||
})
|
||||
observer.observe(anchorRef.current)
|
||||
}
|
||||
return () => observer?.disconnect()
|
||||
}, [containerRef, anchorRef, scrollIntersected, setScrollIntersected])
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
'use client'
|
||||
|
||||
import { useRef } from 'react'
|
||||
import { useScrollIntersection } from './hooks'
|
||||
|
||||
const IntersectionLine = () => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
useScrollIntersection(ref)
|
||||
|
||||
return (
|
||||
<div ref={ref} className='h-[1px] bg-transparent'></div>
|
||||
)
|
||||
}
|
||||
|
||||
export default IntersectionLine
|
||||
@ -0,0 +1,23 @@
|
||||
'use client'
|
||||
|
||||
import type { ReactNode } from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type ListWrapperProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
const ListWrapper = ({
|
||||
children,
|
||||
}: ListWrapperProps) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'px-12 py-2 bg-background-default-subtle',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListWrapper
|
||||
Loading…
Reference in New Issue