dify/web/app/components/plugins/plugin-page/nav-operations.tsx
Coding On Star cb6c04637b
feat(web): add marketplace creator profiles and homepage redesign (#41538)
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: fatelei <fatelei@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: 姜涵煦 <hanxujiang@jianghanxudeMacBook-Pro-2.local>
Co-authored-by: L1nSn0w <l1nsn0w@qq.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
2026-09-04 08:09:45 +00:00

136 lines
4.3 KiB
TypeScript

'use client'
import type { ReactNode } from 'react'
import type { DocPathWithoutLang } from '@/types/doc-paths'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuLinkItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@langgenius/dify-ui/dropdown-menu'
import { IconButton } from '@langgenius/dify-ui/icon-button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { Fragment, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { MARKETPLACE_URL_PREFIX } from '@/config'
import { useDocLink } from '@/context/i18n'
type DropdownItemProps = {
href: string
icon: ReactNode
text: string
}
function DropdownItem({ href, icon, text }: DropdownItemProps) {
return (
<DropdownMenuLinkItem
href={href}
target="_blank"
rel="noopener noreferrer"
className="gap-2 rounded-lg px-3 py-2"
>
{icon}
<span className="system-sm-medium text-text-secondary">{text}</span>
<span className="ml-auto i-ri-arrow-right-up-line size-4 shrink-0 text-text-tertiary" />
</DropdownMenuLinkItem>
)
}
type OptionLabelKey =
| 'requestAPlugin'
| 'pluginDevelopmentGuide'
| 'pluginPublishGuide'
| 'templatePublishingGuide'
function getOptions(docLink: (path: DocPathWithoutLang) => string): {
href: string
icon: ReactNode
labelKey: OptionLabelKey
}[] {
return [
{
href: 'https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml',
icon: <span className="i-ri-plug-line size-4 shrink-0 text-text-tertiary" />,
labelKey: 'requestAPlugin',
},
{
href: docLink('/develop-plugin/getting-started/getting-started-dify-plugin'),
icon: <span className="i-ri-book-open-line size-4 shrink-0 text-text-tertiary" />,
labelKey: 'pluginDevelopmentGuide',
},
{
href: docLink('/develop-plugin/publishing/marketplace-listing/release-overview'),
icon: <span className="i-ri-book-open-line size-4 shrink-0 text-text-tertiary" />,
labelKey: 'pluginPublishGuide',
},
{
href: MARKETPLACE_URL_PREFIX.replace('marketplace', 'creators'),
icon: <span className="i-ri-book-open-line size-4 shrink-0 text-text-tertiary" />,
labelKey: 'templatePublishingGuide',
},
]
}
type SubmitRequestDropdownProps = {
dividerAfterFirst?: boolean
}
type SubmitRequestDropdownMenuProps = SubmitRequestDropdownProps & {
docLink: (path: DocPathWithoutLang) => string
}
// Presentational dropdown. Callers that cannot use useDocLink() -- standalone
// Marketplace SSR -- pass a locale-composed docLink instead.
export function SubmitRequestDropdownMenu({
dividerAfterFirst,
docLink,
}: SubmitRequestDropdownMenuProps) {
const { t } = useTranslation()
const [open, setOpen] = useState(false)
const options = getOptions(docLink)
const guideLabel = t(($) => $['marketplace.home.guide'], { ns: 'plugin' })
return (
<DropdownMenu open={open} onOpenChange={setOpen}>
<Tooltip disabled={open}>
<DropdownMenuTrigger
render={
<TooltipTrigger
render={
<IconButton
aria-label={guideLabel}
size="lg"
className="data-popup-open:bg-state-base-hover data-popup-open:text-text-secondary"
>
<span aria-hidden className="i-ri-book-open-line size-4 shrink-0" />
</IconButton>
}
/>
}
/>
<TooltipContent placement="bottom" role="tooltip">
{guideLabel}
</TooltipContent>
</Tooltip>
<DropdownMenuContent placement="bottom-end" sideOffset={4} className="min-w-50 p-1">
{options.map((option, index) => (
<Fragment key={option.href}>
{dividerAfterFirst && index === 1 && <DropdownMenuSeparator className="my-1" />}
<DropdownItem
href={option.href}
icon={option.icon}
text={t(($) => $[option.labelKey], { ns: 'plugin' })}
/>
</Fragment>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}
export function SubmitRequestDropdown({ dividerAfterFirst }: SubmitRequestDropdownProps) {
const docLink = useDocLink()
return <SubmitRequestDropdownMenu dividerAfterFirst={dividerAfterFirst} docLink={docLink} />
}