mirror of
https://github.com/langgenius/dify.git
synced 2026-05-12 07:37:09 +08:00
chore: templates item ui and learn dify
This commit is contained in:
parent
d9b34fc885
commit
155b7496c5
@ -90,7 +90,14 @@ describe('AppCard', () => {
|
||||
renderComponent({ app: createApp({ description: 'Very long description text' }) })
|
||||
|
||||
const descWrapper = screen.getByText('Very long description text')
|
||||
expect(descWrapper).toHaveClass('line-clamp-4')
|
||||
expect(descWrapper).toHaveClass('line-clamp-2')
|
||||
})
|
||||
|
||||
it('should render category badges', () => {
|
||||
renderComponent({ app: createApp({ categories: ['Search', 'Productivity'] }) })
|
||||
|
||||
expect(screen.getByText('Search')).toBeInTheDocument()
|
||||
expect(screen.getByText('Productivity')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
'use client'
|
||||
import type { App } from '@/models/explore'
|
||||
import type { TryAppSelection } from '@/types/try-app'
|
||||
import { PlusIcon } from '@heroicons/react/20/solid'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { RiInformation2Line } from '@remixicon/react'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
@ -44,8 +42,8 @@ const AppCard = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('group relative col-span-1 flex cursor-pointer flex-col overflow-hidden rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pb-2 shadow-sm transition-all duration-200 ease-in-out hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-lg')}>
|
||||
<div className="flex h-[66px] shrink-0 grow-0 items-center gap-3 px-[14px] pt-[14px] pb-3">
|
||||
<div className="group relative col-span-1 flex h-[142px] cursor-pointer flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pb-3 shadow-xs shadow-shadow-shadow-3">
|
||||
<div className="flex shrink-0 items-center gap-3 px-4 pt-4 pb-2">
|
||||
<div className="relative shrink-0">
|
||||
<AppIcon
|
||||
size="large"
|
||||
@ -55,16 +53,16 @@ const AppCard = ({
|
||||
imageUrl={appBasicInfo.icon_url}
|
||||
/>
|
||||
<AppTypeIcon
|
||||
wrapperClassName="absolute -bottom-0.5 -right-0.5 w-4 h-4 shadow-sm"
|
||||
className="h-3 w-3"
|
||||
wrapperClassName="absolute -right-0.5 -bottom-0.5 size-4 rounded border-components-panel-on-panel-item-bg shadow-sm"
|
||||
className="size-3"
|
||||
type={appBasicInfo.mode}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-0 grow py-px">
|
||||
<div className="flex items-center text-sm leading-5 font-semibold text-text-secondary">
|
||||
<div className="flex w-0 grow flex-col gap-1 py-px">
|
||||
<div className="flex items-center system-md-semibold text-text-secondary">
|
||||
<div className="truncate" title={appBasicInfo.name}>{appBasicInfo.name}</div>
|
||||
</div>
|
||||
<div className="flex items-center text-[10px] leading-[18px] font-medium text-text-tertiary">
|
||||
<div className="flex items-center system-2xs-medium-uppercase text-text-tertiary">
|
||||
{appBasicInfo.mode === AppModeEnum.ADVANCED_CHAT && <div className="truncate">{t('types.advanced', { ns: 'app' }).toUpperCase()}</div>}
|
||||
{appBasicInfo.mode === AppModeEnum.CHAT && <div className="truncate">{t('types.chatbot', { ns: 'app' }).toUpperCase()}</div>}
|
||||
{appBasicInfo.mode === AppModeEnum.AGENT_CHAT && <div className="truncate">{t('types.agent', { ns: 'app' }).toUpperCase()}</div>}
|
||||
@ -73,24 +71,35 @@ const AppCard = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="description-wrapper h-[90px] px-[14px] system-xs-regular text-text-tertiary">
|
||||
<div className="line-clamp-4 group-hover:line-clamp-2">
|
||||
<div className="flex shrink-0 items-start px-4 py-1">
|
||||
<div className="line-clamp-2 min-h-8 flex-1 system-xs-regular text-text-tertiary">
|
||||
{app.description}
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex h-[26px] w-full shrink-0 flex-col gap-2 overflow-hidden px-3">
|
||||
<div className="flex w-full shrink-0 items-center gap-1 rounded-lg p-1">
|
||||
{app.categories.slice(0, 2).map(category => (
|
||||
<div key={category} className="flex min-w-[18px] shrink-0 items-center justify-center gap-0.5 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-[5px] py-[3px] system-2xs-medium-uppercase text-text-tertiary">
|
||||
<span className="i-custom-vender-line-financeAndECommerce-tag-01 size-3 shrink-0" />
|
||||
<span className="whitespace-nowrap">{category}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="pointer-events-none absolute top-0 right-0 bottom-0 w-20 bg-linear-to-r from-components-card-bg-alt-transparent to-components-card-bg-alt" />
|
||||
</div>
|
||||
{isExplore && (canCreate || isTrialApp) && (
|
||||
<div className={cn('absolute right-0 bottom-0 left-0 hidden bg-linear-to-t from-components-panel-gradient-2 from-[60.27%] to-transparent p-4 pt-8 group-hover:flex')}>
|
||||
<div className={cn('grid h-8 w-full grid-cols-1 space-x-2', canCreate && 'grid-cols-2')}>
|
||||
{
|
||||
canCreate && (
|
||||
<Button variant="primary" className="h-7" onClick={() => onCreate()}>
|
||||
<PlusIcon className="mr-1 h-4 w-4" />
|
||||
<span className="mr-1 i-heroicons-plus-20-solid h-4 w-4" />
|
||||
<span className="text-xs">{t('appCard.addToWorkspace', { ns: 'explore' })}</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
<Button className="h-7" onClick={handleTryApp}>
|
||||
<RiInformation2Line className="mr-1 size-4" />
|
||||
<span className="mr-1 i-ri-information-2-line size-4" />
|
||||
<span>{t('appCard.try', { ns: 'explore' })}</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -239,7 +239,7 @@ const Apps = ({
|
||||
<nav
|
||||
className={cn(
|
||||
s.appList,
|
||||
'grid shrink-0 content-start gap-4 px-6 sm:px-12',
|
||||
'grid shrink-0 content-start gap-3 px-6 sm:px-12',
|
||||
)}
|
||||
>
|
||||
{searchFilteredList.map(app => (
|
||||
|
||||
@ -10,19 +10,13 @@
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr))
|
||||
}
|
||||
|
||||
@media (min-width: 1624px) {
|
||||
@media (min-width: 1280px) {
|
||||
.appList {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr))
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1300px) and (max-width: 1624px) {
|
||||
.appList {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr))
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) and (max-width: 1300px) {
|
||||
@media (min-width: 640px) and (max-width: 1279px) {
|
||||
.appList {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr))
|
||||
}
|
||||
|
||||
@ -341,18 +341,20 @@ describe('MainNav', () => {
|
||||
window.removeEventListener(GOTO_ANYTHING_OPEN_EVENT, handleOpen)
|
||||
})
|
||||
|
||||
it('shows hidden Learn Dify in help menu and restores it from localStorage', async () => {
|
||||
it('shows Learn Dify switch in help menu and restores it from localStorage', async () => {
|
||||
localStorage.setItem(LEARN_DIFY_HIDDEN_STORAGE_KEY, 'true')
|
||||
|
||||
renderMainNav()
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'common.mainNav.help.openMenu' }))
|
||||
fireEvent.click(await screen.findByText('common.mainNav.help.learnDify'))
|
||||
expect(await screen.findByText('common.mainNav.help.learnDify')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByRole('switch', { name: 'common.mainNav.help.learnDify' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(localStorage.getItem(LEARN_DIFY_HIDDEN_STORAGE_KEY)).toBe('false')
|
||||
})
|
||||
expect(mockPush).toHaveBeenCalledWith('/explore/apps')
|
||||
expect(mockPush).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('opens workspace settings, members, provider credits, upgrade, and workspace switching actions', async () => {
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@langgenius/dify-ui/dropdown-menu'
|
||||
import { Switch } from '@langgenius/dify-ui/switch'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -24,7 +25,6 @@ import { IS_CLOUD_EDITION } from '@/config'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import { env } from '@/env'
|
||||
import { useRouter } from '@/next/navigation'
|
||||
import { systemFeaturesQueryOptions } from '@/service/system-features'
|
||||
|
||||
const HelpMenu = () => {
|
||||
@ -32,7 +32,6 @@ const HelpMenu = () => {
|
||||
const docLink = useDocLink()
|
||||
const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions())
|
||||
const { langGeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext()
|
||||
const router = useRouter()
|
||||
const [learnDifyHidden, setLearnDifyHidden] = useLearnDifyHiddenState()
|
||||
const [aboutVisible, setAboutVisible] = useState(false)
|
||||
const [open, setOpen] = useState(false)
|
||||
@ -66,21 +65,19 @@ const HelpMenu = () => {
|
||||
/>
|
||||
</DropdownMenuLinkItem>
|
||||
<Support closeAccountDropdown={() => setOpen(false)} />
|
||||
{learnDifyHidden && (
|
||||
<DropdownMenuItem
|
||||
className="mx-0 h-8 gap-1 px-3 py-1.5"
|
||||
onClick={() => {
|
||||
setLearnDifyHidden(false)
|
||||
setOpen(false)
|
||||
router.push('/explore/apps')
|
||||
}}
|
||||
>
|
||||
<MenuItemContent
|
||||
iconClassName="i-ri-graduation-cap-line"
|
||||
label={t('mainNav.help.learnDify', { ns: 'common' })}
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<div className="mx-0 flex h-8 items-center gap-1 rounded-lg py-1 pr-2 pl-3">
|
||||
<span aria-hidden className="i-custom-vender-workflow-docs-extractor size-4 shrink-0 text-text-tertiary" />
|
||||
<span className="min-w-0 flex-1 truncate px-1 py-0.5 system-md-regular text-text-secondary">
|
||||
{t('mainNav.help.learnDify', { ns: 'common' })}
|
||||
</span>
|
||||
<Switch
|
||||
size="md"
|
||||
checked={!learnDifyHidden}
|
||||
aria-label={t('mainNav.help.learnDify', { ns: 'common' })}
|
||||
onClick={event => event.stopPropagation()}
|
||||
onCheckedChange={checked => setLearnDifyHidden(!checked)}
|
||||
/>
|
||||
</div>
|
||||
{IS_CLOUD_EDITION && isCurrentWorkspaceOwner && <Compliance />}
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator className="my-0!" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user