From 946068967becea234bb5df10ab237457ecc5e44f Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 10 Oct 2024 17:47:04 +0800 Subject: [PATCH] feat: finish card components --- .../plugins/test/card/actions.ts | 9 +++ .../(commonLayout)/plugins/test/card/page.tsx | 34 +++++++---- .../plugins/card/base/description.tsx | 6 +- .../plugins/card/base/download-count.tsx | 19 +++++++ web/app/components/plugins/card/card-mock.ts | 2 + .../plugins/card/card-more-info.tsx | 31 +++++++++- .../components/plugins/install-model-item.tsx | 56 +++++++++++++++++++ .../components/plugins/plugin-item/action.tsx | 50 +++++++++++++++++ .../index.tsx} | 41 +++++++++----- web/i18n/de-DE/plugin.ts | 4 ++ web/i18n/en-US/plugin.ts | 6 ++ web/i18n/es-ES/plugin.ts | 4 ++ web/i18n/fa-IR/plugin.ts | 4 ++ web/i18n/fr-FR/plugin.ts | 4 ++ web/i18n/hi-IN/plugin.ts | 4 ++ web/i18n/i18next-config.ts | 1 + web/i18n/it-IT/plugin.ts | 4 ++ web/i18n/ja-JP/plugin.ts | 4 ++ web/i18n/ko-KR/plugin.ts | 4 ++ web/i18n/pl-PL/plugin.ts | 4 ++ web/i18n/pt-BR/plugin.ts | 4 ++ web/i18n/ro-RO/plugin.ts | 4 ++ web/i18n/ru-RU/plugin.ts | 4 ++ web/i18n/tr-TR/plugin.ts | 4 ++ web/i18n/uk-UA/plugin.ts | 4 ++ web/i18n/vi-VN/plugin.ts | 4 ++ web/i18n/zh-Hans/plugin.ts | 6 ++ web/i18n/zh-Hant/plugin.ts | 4 ++ 28 files changed, 297 insertions(+), 28 deletions(-) create mode 100644 web/app/(commonLayout)/plugins/test/card/actions.ts create mode 100644 web/app/components/plugins/card/base/download-count.tsx create mode 100644 web/app/components/plugins/install-model-item.tsx create mode 100644 web/app/components/plugins/plugin-item/action.tsx rename web/app/components/plugins/{plugin-item.tsx => plugin-item/index.tsx} (64%) create mode 100644 web/i18n/de-DE/plugin.ts create mode 100644 web/i18n/en-US/plugin.ts create mode 100644 web/i18n/es-ES/plugin.ts create mode 100644 web/i18n/fa-IR/plugin.ts create mode 100644 web/i18n/fr-FR/plugin.ts create mode 100644 web/i18n/hi-IN/plugin.ts create mode 100644 web/i18n/it-IT/plugin.ts create mode 100644 web/i18n/ja-JP/plugin.ts create mode 100644 web/i18n/ko-KR/plugin.ts create mode 100644 web/i18n/pl-PL/plugin.ts create mode 100644 web/i18n/pt-BR/plugin.ts create mode 100644 web/i18n/ro-RO/plugin.ts create mode 100644 web/i18n/ru-RU/plugin.ts create mode 100644 web/i18n/tr-TR/plugin.ts create mode 100644 web/i18n/uk-UA/plugin.ts create mode 100644 web/i18n/vi-VN/plugin.ts create mode 100644 web/i18n/zh-Hans/plugin.ts create mode 100644 web/i18n/zh-Hant/plugin.ts diff --git a/web/app/(commonLayout)/plugins/test/card/actions.ts b/web/app/(commonLayout)/plugins/test/card/actions.ts new file mode 100644 index 0000000000..42c335ea87 --- /dev/null +++ b/web/app/(commonLayout)/plugins/test/card/actions.ts @@ -0,0 +1,9 @@ +'use server' + +import { revalidatePath } from 'next/cache' + +// Server Actions +export async function handleDelete() { + // revalidatePath only invalidates the cache when the included path is next visited. + revalidatePath('/') +} diff --git a/web/app/(commonLayout)/plugins/test/card/page.tsx b/web/app/(commonLayout)/plugins/test/card/page.tsx index 2a2add60c6..88357c2d33 100644 --- a/web/app/(commonLayout)/plugins/test/card/page.tsx +++ b/web/app/(commonLayout)/plugins/test/card/page.tsx @@ -1,18 +1,21 @@ +import { handleDelete } from './actions' import Card from '@/app/components/plugins/card' import { extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock' import PluginItem from '@/app/components/plugins/plugin-item' +import CardMoreInfo from '@/app/components/plugins/card/card-more-info' +import InstallModelItem from '@/app/components/plugins/install-model-item' const PluginList = async () => { + const pluginList = [toolNotion, extensionDallE, modelGPT4, toolNotion, toolNotion] + return (

Dify Plugin list

- - - - - + {pluginList.map((plugin, index) => ( + + ))}

Install Plugin / Package under bundle

@@ -32,14 +35,25 @@ const PluginList = async () => { />
+

Install model provide

+
+ {pluginList.map((plugin, index) => ( + + ))} +
+

Marketplace Plugin list

- - - - - + {pluginList.map((plugin, index) => ( + + } + /> + ))}
diff --git a/web/app/components/plugins/card/base/description.tsx b/web/app/components/plugins/card/base/description.tsx index 678e7b651e..247a55c628 100644 --- a/web/app/components/plugins/card/base/description.tsx +++ b/web/app/components/plugins/card/base/description.tsx @@ -15,11 +15,11 @@ const Description: FC = ({ }) => { const lineClassName = useMemo(() => { if (descriptionLineRows === 1) - return 'truncate' + return 'h-4 truncate' else if (descriptionLineRows === 2) - return 'line-clamp-2' + return 'h-8 line-clamp-2' else - return 'line-clamp-3' + return 'h-12 line-clamp-3' }, [descriptionLineRows]) return (
diff --git a/web/app/components/plugins/card/base/download-count.tsx b/web/app/components/plugins/card/base/download-count.tsx new file mode 100644 index 0000000000..0c28e6970e --- /dev/null +++ b/web/app/components/plugins/card/base/download-count.tsx @@ -0,0 +1,19 @@ +import { RiInstallLine } from '@remixicon/react' +import { formatNumber } from '@/utils/format' + +type Props = { + downloadCount: number +} + +const DownloadCount = ({ + downloadCount, +}: Props) => { + return ( +
+ +
{formatNumber(downloadCount)}
+
+ ) +} + +export default DownloadCount diff --git a/web/app/components/plugins/card/card-mock.ts b/web/app/components/plugins/card/card-mock.ts index 6718c50740..d411288db7 100644 --- a/web/app/components/plugins/card/card-mock.ts +++ b/web/app/components/plugins/card/card-mock.ts @@ -23,6 +23,7 @@ export const extensionDallE = { name: 'DALL-E', version: '1.1.0', latest_version: '1.2.0', + install_count: 1234, icon: 'https://via.placeholder.com/150', label: { 'en-US': 'DALL-E', @@ -40,6 +41,7 @@ export const modelGPT4 = { name: 'GPT-4', version: '1.0.0', latest_version: '1.0.0', + install_count: 99999, icon: 'https://via.placeholder.com/150', label: { 'en-US': 'GPT-4', diff --git a/web/app/components/plugins/card/card-more-info.tsx b/web/app/components/plugins/card/card-more-info.tsx index b808cecd96..8c9d324c35 100644 --- a/web/app/components/plugins/card/card-more-info.tsx +++ b/web/app/components/plugins/card/card-more-info.tsx @@ -1,3 +1,32 @@ -const CardMoreInfo = () => { +import DownloadCount from './base/download-count' +type Props = { + downloadCount: number + tags: string[] } + +const CardMoreInfo = ({ + downloadCount, + tags, +}: Props) => { + return ( +
+ + {tags && tags.length > 0 && ( + <> +
·
+
+ {tags.map(tag => ( +
+ # + {tag} +
+ ))} +
+ + )} +
+ ) +} + +export default CardMoreInfo diff --git a/web/app/components/plugins/install-model-item.tsx b/web/app/components/plugins/install-model-item.tsx new file mode 100644 index 0000000000..906f9cee94 --- /dev/null +++ b/web/app/components/plugins/install-model-item.tsx @@ -0,0 +1,56 @@ +import type { FC } from 'react' +import React from 'react' +import { RiVerifiedBadgeLine } from '@remixicon/react' +import Badge from '../base/badge' +import type { Plugin } from './types' +import Description from './card/base/description' +import Icon from './card/base/icon' +import Title from './card/base/title' +import DownloadCount from './card/base/download-count' +import { getLocaleOnServer } from '@/i18n/server' +import cn from '@/utils/classnames' + +type Props = { + className?: string + payload: Plugin +} + +const PluginItem: FC = async ({ + className, + payload, +}) => { + const locale = getLocaleOnServer() + const { org, label } = payload + + return ( +
+
+ {/* Header */} +
+ +
+
+ + <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" /> + </div> + <div className='mb-1 flex justify-between items-center h-4'> + <div className='flex items-center'> + <div className='text-text-tertiary system/xs-regular'>{org}</div> + <div className='mx-2 text-text-quaternary system-xs-regular'>·</div> + <DownloadCount downloadCount={payload.install_count || 0} /> + </div> + </div> + </div> + </div> + <Description className='mt-3' text={payload.brief[locale]} descriptionLineRows={2}></Description> + <div className='mt-3 flex space-x-0.5'> + {['LLM', 'text embedding', 'speech2text'].map(tag => ( + <Badge key={tag} text={tag} /> + ))} + </div> + </div> + </div> + ) +} + +export default PluginItem diff --git a/web/app/components/plugins/plugin-item/action.tsx b/web/app/components/plugins/plugin-item/action.tsx new file mode 100644 index 0000000000..86198b9d70 --- /dev/null +++ b/web/app/components/plugins/plugin-item/action.tsx @@ -0,0 +1,50 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { useRouter } from 'next/navigation' +import { RiDeleteBinLine, RiInformation2Line, RiLoopLeftLine } from '@remixicon/react' + +type Props = { + pluginId: string + isShowFetchNewVersion: boolean + isShowInfo: boolean + isShowDelete: boolean + onDelete: () => void +} + +const Action: FC<Props> = ({ + isShowFetchNewVersion, + isShowInfo, + isShowDelete, + onDelete, +}) => { + const router = useRouter() + + const handleFetchNewVersion = () => { } + const handleShowInfo = () => { + router.refresh() // refresh the page ... + } + // const handleDelete = () => { } + return ( + <div className='flex space-x-1'> + {isShowFetchNewVersion + && <div className='p-0.5 cursor-pointer' onClick={handleFetchNewVersion}> + <RiLoopLeftLine className='w-5 h-5 text-text-tertiary' /> + </div> + } + { + isShowInfo + && <div className='p-0.5 cursor-pointer' onClick={handleShowInfo}> + <RiInformation2Line className='w-5 h-5 text-text-tertiary' /> + </div> + } + { + isShowDelete + && <div className='p-0.5 cursor-pointer' onClick={onDelete}> + <RiDeleteBinLine className='w-5 h-5 text-text-tertiary' /> + </div> + } + </div> + ) +} +export default React.memo(Action) diff --git a/web/app/components/plugins/plugin-item.tsx b/web/app/components/plugins/plugin-item/index.tsx similarity index 64% rename from web/app/components/plugins/plugin-item.tsx rename to web/app/components/plugins/plugin-item/index.tsx index 6625a7f850..65c68ddf18 100644 --- a/web/app/components/plugins/plugin-item.tsx +++ b/web/app/components/plugins/plugin-item/index.tsx @@ -1,28 +1,32 @@ import type { FC } from 'react' import React from 'react' import { RiArrowRightUpLine, RiLoginCircleLine, RiVerifiedBadgeLine } from '@remixicon/react' -import { Github } from '../base/icons/src/public/common' -import Badge from '../base/badge' -import type { Plugin } from './types' -import CornerMark from './card/base/corner-mark' -import Description from './card/base/description' -import Icon from './card/base/icon' -import OrgInfo from './card/base/org-info' -import Title from './card/base/title' - +import { Github } from '../../base/icons/src/public/common' +import Badge from '../../base/badge' +import type { Plugin } from '../types' +import CornerMark from '../card/base/corner-mark' +import Description from '../card/base/description' +import Icon from '../card/base/icon' +import OrgInfo from '../card/base/org-info' +import Title from '../card/base/title' +import Action from './action' +import { getLocaleOnServer, useTranslation as translate } from '@/i18n/server' import cn from '@/utils/classnames' -import { getLocaleOnServer } from '@/i18n/server' type Props = { className?: string payload: Plugin + onDelete: () => void } -const PluginItem: FC<Props> = ({ +const PluginItem: FC<Props> = async ({ className, payload, + onDelete, }) => { const locale = getLocaleOnServer() + const { t: pluginI8n } = await translate(locale, 'plugin') + const { type, name, org, label } = payload const hasNewVersion = payload.latest_version !== payload.version @@ -39,7 +43,16 @@ const PluginItem: FC<Props> = ({ <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" /> <Badge className='ml-1' text={payload.version} hasRedCornerMark={hasNewVersion} /> </div> - <Description text={payload.brief[locale]} descriptionLineRows={1}></Description> + <div className='flex items-center justify-between'> + <Description text={payload.brief[locale]} descriptionLineRows={1}></Description> + <Action + pluginId='xxx' + isShowFetchNewVersion={hasNewVersion} + isShowInfo + isShowDelete + onDelete={onDelete} + /> + </div> </div> </div> </div> @@ -54,12 +67,12 @@ const PluginItem: FC<Props> = ({ <div className='mx-2 text-text-quaternary system-xs-regular'>·</div> <div className='flex text-text-tertiary system-xs-regular space-x-1'> <RiLoginCircleLine className='w-4 h-4' /> - <span>2 sets of endpoints enabled</span> + <span>{pluginI8n('endpointsEnabled', { num: 2 })}</span> </div> </div> <div className='flex items-center'> - <div className='mr-1 text-text-tertiary system-2xs-medium-uppercase'>From</div> + <a href='' target='_blank' className='mr-1 text-text-tertiary system-2xs-medium-uppercase'>{pluginI8n('from')}</a> <div className='flex items-center space-x-0.5 text-text-secondary'> <Github className='ml-1 w-3 h-3' /> <div className='system-2xs-semibold-uppercase'>GitHub</div> diff --git a/web/i18n/de-DE/plugin.ts b/web/i18n/de-DE/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/de-DE/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts new file mode 100644 index 0000000000..55acb354ab --- /dev/null +++ b/web/i18n/en-US/plugin.ts @@ -0,0 +1,6 @@ +const translation = { + from: 'From', + endpointsEnabled: '{{num}} sets of endpoints enabled', +} + +export default translation diff --git a/web/i18n/es-ES/plugin.ts b/web/i18n/es-ES/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/es-ES/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/fa-IR/plugin.ts b/web/i18n/fa-IR/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/fa-IR/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/fr-FR/plugin.ts b/web/i18n/fr-FR/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/fr-FR/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/hi-IN/plugin.ts b/web/i18n/hi-IN/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/hi-IN/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/i18next-config.ts b/web/i18n/i18next-config.ts index 661475ea21..be8b4c46e1 100644 --- a/web/i18n/i18next-config.ts +++ b/web/i18n/i18next-config.ts @@ -28,6 +28,7 @@ const loadLangResources = (lang: string) => ({ tools: require(`./${lang}/tools`).default, workflow: require(`./${lang}/workflow`).default, runLog: require(`./${lang}/run-log`).default, + plugin: require(`./${lang}/plugin`).default, }, }) diff --git a/web/i18n/it-IT/plugin.ts b/web/i18n/it-IT/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/it-IT/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/ja-JP/plugin.ts b/web/i18n/ja-JP/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/ja-JP/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/ko-KR/plugin.ts b/web/i18n/ko-KR/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/ko-KR/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/pl-PL/plugin.ts b/web/i18n/pl-PL/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/pl-PL/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/pt-BR/plugin.ts b/web/i18n/pt-BR/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/pt-BR/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/ro-RO/plugin.ts b/web/i18n/ro-RO/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/ro-RO/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/ru-RU/plugin.ts b/web/i18n/ru-RU/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/ru-RU/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/tr-TR/plugin.ts b/web/i18n/tr-TR/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/tr-TR/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/uk-UA/plugin.ts b/web/i18n/uk-UA/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/uk-UA/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/vi-VN/plugin.ts b/web/i18n/vi-VN/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/vi-VN/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts new file mode 100644 index 0000000000..e540d590f6 --- /dev/null +++ b/web/i18n/zh-Hans/plugin.ts @@ -0,0 +1,6 @@ +const translation = { + from: '来自', + endpointsEnabled: '{{num}} 组端点已启用', +} + +export default translation diff --git a/web/i18n/zh-Hant/plugin.ts b/web/i18n/zh-Hant/plugin.ts new file mode 100644 index 0000000000..928649474b --- /dev/null +++ b/web/i18n/zh-Hant/plugin.ts @@ -0,0 +1,4 @@ +const translation = { +} + +export default translation