diff --git a/web/app/(commonLayout)/plugins/test/card/page.tsx b/web/app/(commonLayout)/plugins/test/card/page.tsx
index facff918bc..a916606dfc 100644
--- a/web/app/(commonLayout)/plugins/test/card/page.tsx
+++ b/web/app/(commonLayout)/plugins/test/card/page.tsx
@@ -1,5 +1,5 @@
import Card from '@/app/components/plugins/card'
-import { extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card-mock'
+import { extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock'
import PluginItem from '@/app/components/plugins/plugin-item'
const PluginList = async () => {
diff --git a/web/app/components/plugins/card.tsx b/web/app/components/plugins/card.tsx
deleted file mode 100644
index c3897e22c6..0000000000
--- a/web/app/components/plugins/card.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import React, { useMemo } from 'react'
-import { RiCheckLine, RiVerifiedBadgeLine } from '@remixicon/react'
-import type { FC } from 'react'
-import { LeftCorner } from '../base/icons/src/vender/plugin'
-import type { Plugin } from './types'
-import { getLocaleOnServer } from '@/i18n/server'
-import cn from '@/utils/classnames'
-
-export const CornerMark = ({ text }: { text: string }) => {
- return (
-
- )
-}
-
-export const Icon = ({
- className,
- src,
- installed = false,
-}: {
- className?: string
- src: string
- installed?: boolean
-}) => {
- return (
-
- )
-}
-
-export const Title = ({
- title,
-}: {
- title: string
-}) => {
- return (
-
- {title}
-
- )
-}
-
-export const OrgInfo = ({
- className,
- orgName,
- packageName,
-}: {
- className?: string
- orgName: string
- packageName: string
-}) => {
- return
- {orgName}
- /
- {packageName}
-
-}
-
-type DescriptionProps = {
- className?: string
- text: string
- descriptionLineRows: number
-}
-
-export const Description: FC = ({
- className,
- text,
- descriptionLineRows,
-}) => {
- const lineClassName = useMemo(() => {
- if (descriptionLineRows === 1)
- return 'truncate'
- else if (descriptionLineRows === 2)
- return 'line-clamp-2'
- else
- return 'line-clamp-3'
- }, [descriptionLineRows])
- return (
-
- {text}
-
- )
-}
-
-type Props = {
- className?: string
- payload: Plugin
- installed?: boolean
- descriptionLineRows?: number
- footer?: React.ReactNode
-}
-
-const Card = ({
- className,
- payload,
- installed,
- descriptionLineRows = 2,
- footer,
-}: Props) => {
- const locale = getLocaleOnServer()
-
- const { type, name, org, label } = payload
- return (
-
-
- {/* Header */}
-
-
- {footer &&
{footer}
}
-
- )
-}
-
-export default Card
diff --git a/web/app/components/plugins/card/base/corner-mark.tsx b/web/app/components/plugins/card/base/corner-mark.tsx
new file mode 100644
index 0000000000..cdb9eb5417
--- /dev/null
+++ b/web/app/components/plugins/card/base/corner-mark.tsx
@@ -0,0 +1,12 @@
+import { LeftCorner } from '../../../base/icons/src/vender/plugin'
+
+const CornerMark = ({ text }: { text: string }) => {
+ return (
+
+ )
+}
+
+export default CornerMark
diff --git a/web/app/components/plugins/card/base/description.tsx b/web/app/components/plugins/card/base/description.tsx
new file mode 100644
index 0000000000..678e7b651e
--- /dev/null
+++ b/web/app/components/plugins/card/base/description.tsx
@@ -0,0 +1,31 @@
+import type { FC } from 'react'
+import React, { useMemo } from 'react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ text: string
+ descriptionLineRows: number
+}
+
+const Description: FC = ({
+ className,
+ text,
+ descriptionLineRows,
+}) => {
+ const lineClassName = useMemo(() => {
+ if (descriptionLineRows === 1)
+ return 'truncate'
+ else if (descriptionLineRows === 2)
+ return 'line-clamp-2'
+ else
+ return 'line-clamp-3'
+ }, [descriptionLineRows])
+ return (
+
+ {text}
+
+ )
+}
+
+export default Description
diff --git a/web/app/components/plugins/card/base/icon.tsx b/web/app/components/plugins/card/base/icon.tsx
new file mode 100644
index 0000000000..60be58007f
--- /dev/null
+++ b/web/app/components/plugins/card/base/icon.tsx
@@ -0,0 +1,31 @@
+import { RiCheckLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+
+const Icon = ({
+ className,
+ src,
+ installed = false,
+}: {
+ className?: string
+ src: string
+ installed?: boolean
+}) => {
+ return (
+
+ )
+}
+
+export default Icon
diff --git a/web/app/components/plugins/card/base/org-info.tsx b/web/app/components/plugins/card/base/org-info.tsx
new file mode 100644
index 0000000000..972b871375
--- /dev/null
+++ b/web/app/components/plugins/card/base/org-info.tsx
@@ -0,0 +1,19 @@
+import cn from '@/utils/classnames'
+
+const OrgInfo = ({
+ className,
+ orgName,
+ packageName,
+}: {
+ className?: string
+ orgName: string
+ packageName: string
+}) => {
+ return
+ {orgName}
+ /
+ {packageName}
+
+}
+
+export default OrgInfo
diff --git a/web/app/components/plugins/card/base/title.tsx b/web/app/components/plugins/card/base/title.tsx
new file mode 100644
index 0000000000..bfdcd7fc2b
--- /dev/null
+++ b/web/app/components/plugins/card/base/title.tsx
@@ -0,0 +1,13 @@
+const Title = ({
+ title,
+}: {
+ title: string
+}) => {
+ return (
+
+ {title}
+
+ )
+}
+
+export default Title
diff --git a/web/app/components/plugins/card-mock.ts b/web/app/components/plugins/card/card-mock.ts
similarity index 97%
rename from web/app/components/plugins/card-mock.ts
rename to web/app/components/plugins/card/card-mock.ts
index 27f7fd5386..a3e75a3573 100644
--- a/web/app/components/plugins/card-mock.ts
+++ b/web/app/components/plugins/card/card-mock.ts
@@ -1,4 +1,4 @@
-import { PluginType } from './types'
+import { PluginType } from '../types'
export const toolNotion = {
type: PluginType.tool,
diff --git a/web/app/components/plugins/card-more-info.tsx b/web/app/components/plugins/card/card-more-info.tsx
similarity index 100%
rename from web/app/components/plugins/card-more-info.tsx
rename to web/app/components/plugins/card/card-more-info.tsx
diff --git a/web/app/components/plugins/card/index.tsx b/web/app/components/plugins/card/index.tsx
new file mode 100644
index 0000000000..1cec64491e
--- /dev/null
+++ b/web/app/components/plugins/card/index.tsx
@@ -0,0 +1,58 @@
+import React from 'react'
+import { RiVerifiedBadgeLine } from '@remixicon/react'
+import type { Plugin } from '../types'
+import CornerMark from './base/corner-mark'
+import Icon from './base/icon'
+import Title from './base/title'
+import OrgInfo from './base/org-info'
+import Description from './base/description'
+import cn from '@/utils/classnames'
+import { getLocaleOnServer } from '@/i18n/server'
+
+type Props = {
+ className?: string
+ payload: Plugin
+ installed?: boolean
+ descriptionLineRows?: number
+ footer?: React.ReactNode
+}
+
+const Card = ({
+ className,
+ payload,
+ installed,
+ descriptionLineRows = 2,
+ footer,
+}: Props) => {
+ const locale = getLocaleOnServer()
+
+ const { type, name, org, label } = payload
+ return (
+
+
+ {/* Header */}
+
+
+ {footer &&
{footer}
}
+
+ )
+}
+
+export default Card
diff --git a/web/app/components/plugins/plugin-item.tsx b/web/app/components/plugins/plugin-item.tsx
index d685517ba4..c2d09cfa73 100644
--- a/web/app/components/plugins/plugin-item.tsx
+++ b/web/app/components/plugins/plugin-item.tsx
@@ -3,7 +3,12 @@ import React from 'react'
import { RiArrowRightUpLine, RiVerifiedBadgeLine } from '@remixicon/react'
import { Github } from '../base/icons/src/public/common'
import type { Plugin } from './types'
-import { CornerMark, Description, Icon, OrgInfo, Title } from '@/app/components/plugins/card'
+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 cn from '@/utils/classnames'
import { getLocaleOnServer } from '@/i18n/server'