mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 19:59:50 +08:00
update the plugins page
This commit is contained in:
parent
6613b8f2e0
commit
21193c2fbf
94
web/app/(commonLayout)/plugins/Container.tsx
Normal file
94
web/app/(commonLayout)/plugins/Container.tsx
Normal file
|
@ -0,0 +1,94 @@
|
|||
'use client'
|
||||
|
||||
import { useMemo, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiArrowRightUpLine,
|
||||
RiBugLine,
|
||||
RiDragDropLine,
|
||||
RiEqualizer2Line,
|
||||
} from '@remixicon/react'
|
||||
import InstallPluginDropdown from './InstallPluginDropdown'
|
||||
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
|
||||
import Button from '@/app/components/base/button'
|
||||
import TabSlider from '@/app/components/base/tab-slider'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
const Container = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const options = useMemo(() => {
|
||||
return [
|
||||
{ value: 'plugins', text: t('common.menus.plugins') },
|
||||
{ value: 'discover', text: 'Discover in Marketplace' },
|
||||
]
|
||||
}, [t])
|
||||
|
||||
const [activeTab, setActiveTab] = useTabSearchParams({
|
||||
defaultTab: 'plugins',
|
||||
})
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className='grow relative flex flex-col rounded-t-xl bg-components-panel-bg border-t
|
||||
border-divider-subtle overflow-y-auto'>
|
||||
<div className='flex min-h-[60px] px-12 pt-4 pb-2 items-center self-stretch gap-1'>
|
||||
<div className='flex justify-between items-center w-full'>
|
||||
<div className='flex-1'>
|
||||
<TabSlider
|
||||
value={activeTab}
|
||||
onChange={newActiveTab => setActiveTab(newActiveTab)}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-shrink-0 items-center gap-1'>
|
||||
<InstallPluginDropdown />
|
||||
<Tooltip
|
||||
triggerMethod='click'
|
||||
popupContent={
|
||||
<>
|
||||
<div className='flex items-center gap-1 self-stretch'>
|
||||
<span className='flex flex-col justify-center items-start flex-grow flex-shrink-0 basis-0 text-text-secondary system-sm-semibold'>Debugging</span>
|
||||
<div className='flex items-center gap-0.5 text-text-accent-light-mode-only cursor-pointer'>
|
||||
<span className='system-xs-medium'>View docs</span>
|
||||
<RiArrowRightUpLine className='w-3 h-3' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col items-start gap-0.5 self-stretch'>
|
||||
<div className='flex items-center gap-1 self-stretch'>
|
||||
<span className='flex w-10 flex-col justify-center items-start text-text-tertiary system-xs-medium'>Port</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
popupClassName='flex flex-col items-start w-[256px] px-4 py-3.5 gap-1 border border-components-panel-border
|
||||
rounded-xl bg-components-tooltip-bg shadows-shadow-lg'
|
||||
asChild={false}
|
||||
position='bottom'
|
||||
>
|
||||
<Button className='w-full h-full p-2 text-components-button-secondary-text'>
|
||||
<RiBugLine className='w-4 h-4' />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Button className='w-full h-full p-2 text-components-button-secondary-text'>
|
||||
<RiEqualizer2Line className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col flex-grow pt-1 pb-3 px-12 justify-center items-start gap-3 self-stretch'>
|
||||
<div className='h-px self-stretch bg-divider-subtle'></div>
|
||||
<div className='flex items-center gap-2 self-stretch'>
|
||||
{/* Content for active tab will go here */}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-center py-4 gap-2 text-text-quaternary'>
|
||||
<RiDragDropLine className='w-4 h-4' />
|
||||
<span className='system-xs-regular'>Drop plugin package here to install</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Container
|
67
web/app/(commonLayout)/plugins/InstallPluginDropdown.tsx
Normal file
67
web/app/(commonLayout)/plugins/InstallPluginDropdown.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
'use client'
|
||||
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { RiAddLine, RiArrowDownSLine } from '@remixicon/react'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { MagicBox } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
|
||||
import { FileZip } from '@/app/components/base/icons/src/vender/solid/files'
|
||||
import { Github } from '@/app/components/base/icons/src/vender/solid/general'
|
||||
|
||||
const InstallPluginDropdown = () => {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||
const menuRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (menuRef.current && !menuRef.current.contains(event.target as Node))
|
||||
setIsMenuOpen(false)
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="relative" ref={menuRef}>
|
||||
<Button
|
||||
className='w-full h-full p-2 text-components-button-secondary-text'
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
>
|
||||
<RiAddLine className='w-4 h-4' />
|
||||
<span className='pl-1'>Install plugin</span>
|
||||
<RiArrowDownSLine className='w-4 h-4 ml-1' />
|
||||
</Button>
|
||||
{isMenuOpen && (
|
||||
<div className='flex flex-col items-start absolute z-1000 top-full left-0 mt-1 p-1 pb-2
|
||||
w-[200px] bg-components-panel-bg-blur border border-components-panel-border rounded-xl
|
||||
shadows-shadow-lg'>
|
||||
<span className='flex pt-1 pb-0.5 pl-2 pr-3 items-start self-stretch text-text-tertiary
|
||||
system-xs-medium-uppercase'>
|
||||
Install Form
|
||||
</span>
|
||||
{[
|
||||
{ icon: MagicBox, text: 'Marketplace', action: 'marketplace' },
|
||||
{ icon: Github, text: 'GitHub', action: 'github' },
|
||||
{ icon: FileZip, text: 'Local Package File', action: 'local' },
|
||||
].map(({ icon: Icon, text, action }) => (
|
||||
<div
|
||||
key={action}
|
||||
className='flex items-center w-full px-2 py-1.5 gap-1 rounded-lg hover:bg-state-base-hover cursor-pointer'
|
||||
onClick={() => {
|
||||
console.log(action)
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon className="w-4 h-4 text-text-tertiary" />
|
||||
<span className='px-1 text-text-secondary system-md-regular'>{text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default InstallPluginDropdown
|
13
web/app/(commonLayout)/plugins/page.tsx
Normal file
13
web/app/(commonLayout)/plugins/page.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import Container from './Container'
|
||||
|
||||
const PluginList = async () => {
|
||||
return (
|
||||
<Container />
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = {
|
||||
title: 'Plugins - Dify',
|
||||
}
|
||||
|
||||
export default PluginList
|
28
web/app/components/base/badge/index.css
Normal file
28
web/app/components/base/badge/index.css
Normal file
|
@ -0,0 +1,28 @@
|
|||
@tailwind components;
|
||||
|
||||
@layer components {
|
||||
.badge {
|
||||
@apply inline-flex justify-center items-center text-text-tertiary border border-divider-deep
|
||||
}
|
||||
|
||||
.badge-l {
|
||||
@apply rounded-md gap-1 min-w-6
|
||||
}
|
||||
|
||||
/* m is for the regular button */
|
||||
.badge-m {
|
||||
@apply rounded-md gap-[3px] min-w-5
|
||||
}
|
||||
|
||||
.badge-s {
|
||||
@apply rounded-[5px] gap-0.5 min-w-[18px]
|
||||
}
|
||||
|
||||
.badge.badge-warning {
|
||||
@apply text-text-warning border border-text-warning
|
||||
}
|
||||
|
||||
.badge.badge-accent {
|
||||
@apply text-text-accent-secondary border border-text-accent-secondary
|
||||
}
|
||||
}
|
81
web/app/components/base/badge/index.tsx
Normal file
81
web/app/components/base/badge/index.tsx
Normal file
|
@ -0,0 +1,81 @@
|
|||
import type { CSSProperties, ReactNode } from 'react'
|
||||
import React from 'react'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import classNames from '@/utils/classnames'
|
||||
import './index.css'
|
||||
|
||||
enum BadgeState {
|
||||
Warning = 'warning',
|
||||
Accent = 'accent',
|
||||
Default = '',
|
||||
}
|
||||
|
||||
const BadgeVariants = cva(
|
||||
'badge',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
s: 'badge-s',
|
||||
m: 'badge-m',
|
||||
l: 'badge-l',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: 'm',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
type BadgeProps = {
|
||||
size?: 's' | 'm' | 'l'
|
||||
iconOnly?: boolean
|
||||
uppercase?: boolean
|
||||
state?: BadgeState
|
||||
styleCss?: CSSProperties
|
||||
children?: ReactNode
|
||||
} & React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof BadgeVariants>
|
||||
|
||||
function getBadgeState(state: BadgeState) {
|
||||
switch (state) {
|
||||
case BadgeState.Warning:
|
||||
return 'badge-warning'
|
||||
case BadgeState.Accent:
|
||||
return 'badge-accent'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const Badge: React.FC<BadgeProps> = ({
|
||||
className,
|
||||
size,
|
||||
state = BadgeState.Default,
|
||||
iconOnly = false,
|
||||
uppercase = false,
|
||||
styleCss,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
BadgeVariants({ size, className }),
|
||||
getBadgeState(state),
|
||||
size === 's'
|
||||
? (iconOnly ? 'p-[3px]' : 'px-[5px] py-[3px]')
|
||||
: size === 'l'
|
||||
? (iconOnly ? 'p-1.5' : 'px-2 py-1')
|
||||
: (iconOnly ? 'p-1' : 'px-[5px] py-[2px]'),
|
||||
uppercase ? 'system-2xs-medium-uppercase' : 'system-2xs-medium',
|
||||
)}
|
||||
style={styleCss}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Badge.displayName = 'Badge'
|
||||
|
||||
export default Badge
|
||||
export { Badge, BadgeState, BadgeVariants }
|
|
@ -0,0 +1,8 @@
|
|||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Group">
|
||||
<path id="Vector" d="M5.6475 8.0115L0.333496 5.05884V11.3335C0.333491 11.4524 0.365258 11.569 0.425506 11.6715C0.485754 11.7739 0.572294 11.8584 0.676163 11.9162L6.3335 15.0588V9.17684C6.33344 8.93907 6.26981 8.70565 6.14919 8.50075C6.02857 8.29586 5.85536 8.12694 5.6475 8.0115Z" fill="#354052"/>
|
||||
<path id="Vector_2" d="M7.66699 9.17684V15.0588L13.3243 11.9162C13.4282 11.8584 13.5147 11.7739 13.575 11.6715C13.6352 11.569 13.667 11.4524 13.667 11.3335V5.05884L8.35299 8.0115C8.14513 8.12694 7.97192 8.29586 7.8513 8.50075C7.73068 8.70565 7.66705 8.93907 7.66699 9.17684Z" fill="#676F83"/>
|
||||
<path id="Vector_3" d="M10.1913 2.34351C9.804 3.33351 8.588 4.00017 7 4.00017C5.412 4.00017 4.196 3.33351 3.80867 2.34351L1 3.90417L6.35267 6.87817C6.5507 6.98815 6.77348 7.04586 7 7.04586C7.22652 7.04586 7.4493 6.98815 7.64733 6.87817L13 3.90417L10.1913 2.34351Z" fill="#676F83"/>
|
||||
<path id="Vector_4" d="M7 2.66675C8.10457 2.66675 9 2.21903 9 1.66675C9 1.11446 8.10457 0.666748 7 0.666748C5.89543 0.666748 5 1.11446 5 1.66675C5 2.21903 5.89543 2.66675 7 2.66675Z" fill="#354052"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,6 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon">
|
||||
<path id="Vector" d="M3.99999 1.33325H7.99999V5.33325C7.99999 6.06963 8.59692 6.66659 9.33332 6.66659H13.3333V13.3333C13.3333 14.0697 12.7364 14.6666 12 14.6666H6.66666V13.3333H7.99999V11.9999H6.66666V10.6666H7.99999V9.33325H6.66666V7.99992H5.33332V9.33325H6.66666V10.6666H5.33332V11.9999H6.66666V13.3333H5.33332V14.6666H3.99999C3.26361 14.6666 2.66666 14.0697 2.66666 13.3333V2.66659C2.66666 1.93021 3.26361 1.33325 3.99999 1.33325Z" fill="#676F83"/>
|
||||
<path id="Vector_2" opacity="0.5" d="M12.9428 4.99993C13.0415 5.09868 13.1232 5.21133 13.1859 5.33327H9.33334V1.48071C9.45528 1.54338 9.56794 1.62504 9.66668 1.72379L12.9428 4.99993Z" fill="#676F83"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 775 B |
|
@ -0,0 +1,5 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon">
|
||||
<path id="Vector" d="M8 1C4.1325 1 1 4.1325 1 8C1 11.0975 3.00375 13.7137 5.78625 14.6413C6.13625 14.7025 6.2675 14.4925 6.2675 14.3088C6.2675 14.1425 6.25875 13.5913 6.25875 13.005C4.5 13.3288 4.045 12.5763 3.905 12.1825C3.82625 11.9812 3.485 11.36 3.1875 11.1937C2.9425 11.0625 2.5925 10.7387 3.17875 10.73C3.73 10.7212 4.12375 11.2375 4.255 11.4475C4.885 12.5062 5.89125 12.2088 6.29375 12.025C6.355 11.57 6.53875 11.2638 6.74 11.0887C5.1825 10.9137 3.555 10.31 3.555 7.6325C3.555 6.87125 3.82625 6.24125 4.2725 5.75125C4.2025 5.57625 3.9575 4.85875 4.3425 3.89625C4.3425 3.89625 4.92875 3.7125 6.2675 4.61375C6.8275 4.45625 7.4225 4.3775 8.0175 4.3775C8.6125 4.3775 9.2075 4.45625 9.7675 4.61375C11.1063 3.70375 11.6925 3.89625 11.6925 3.89625C12.0775 4.85875 11.8325 5.57625 11.7625 5.75125C12.2087 6.24125 12.48 6.8625 12.48 7.6325C12.48 10.3187 10.8438 10.9137 9.28625 11.0887C9.54 11.3075 9.75875 11.7275 9.75875 12.3837C9.75875 13.32 9.75 14.0725 9.75 14.3088C9.75 14.4925 9.88125 14.7113 10.2312 14.6413C11.6209 14.1721 12.8284 13.279 13.6839 12.0877C14.5393 10.8963 14.9996 9.46668 15 8C15 4.1325 11.8675 1 8 1Z" fill="#676F83"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
66
web/app/components/base/icons/src/vender/other/Group.json
Normal file
66
web/app/components/base/icons/src/vender/other/Group.json
Normal file
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "14",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 14 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Group"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector",
|
||||
"d": "M5.6475 8.0115L0.333496 5.05884V11.3335C0.333491 11.4524 0.365258 11.569 0.425506 11.6715C0.485754 11.7739 0.572294 11.8584 0.676163 11.9162L6.3335 15.0588V9.17684C6.33344 8.93907 6.26981 8.70565 6.14919 8.50075C6.02857 8.29586 5.85536 8.12694 5.6475 8.0115Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_2",
|
||||
"d": "M7.66699 9.17684V15.0588L13.3243 11.9162C13.4282 11.8584 13.5147 11.7739 13.575 11.6715C13.6352 11.569 13.667 11.4524 13.667 11.3335V5.05884L8.35299 8.0115C8.14513 8.12694 7.97192 8.29586 7.8513 8.50075C7.73068 8.70565 7.66705 8.93907 7.66699 9.17684Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_3",
|
||||
"d": "M10.1913 2.34351C9.804 3.33351 8.588 4.00017 7 4.00017C5.412 4.00017 4.196 3.33351 3.80867 2.34351L1 3.90417L6.35267 6.87817C6.5507 6.98815 6.77348 7.04586 7 7.04586C7.22652 7.04586 7.4493 6.98815 7.64733 6.87817L13 3.90417L10.1913 2.34351Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_4",
|
||||
"d": "M7 2.66675C8.10457 2.66675 9 2.21903 9 1.66675C9 1.11446 8.10457 0.666748 7 0.666748C5.89543 0.666748 5 1.11446 5 1.66675C5 2.21903 5.89543 2.66675 7 2.66675Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Group"
|
||||
}
|
16
web/app/components/base/icons/src/vender/other/Group.tsx
Normal file
16
web/app/components/base/icons/src/vender/other/Group.tsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Group.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Group'
|
||||
|
||||
export default Icon
|
|
@ -1 +1,2 @@
|
|||
export { default as Generator } from './Generator'
|
||||
export { default as Group } from './Group'
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector",
|
||||
"d": "M3.99999 1.33325H7.99999V5.33325C7.99999 6.06963 8.59692 6.66659 9.33332 6.66659H13.3333V13.3333C13.3333 14.0697 12.7364 14.6666 12 14.6666H6.66666V13.3333H7.99999V11.9999H6.66666V10.6666H7.99999V9.33325H6.66666V7.99992H5.33332V9.33325H6.66666V10.6666H5.33332V11.9999H6.66666V13.3333H5.33332V14.6666H3.99999C3.26361 14.6666 2.66666 14.0697 2.66666 13.3333V2.66659C2.66666 1.93021 3.26361 1.33325 3.99999 1.33325Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_2",
|
||||
"opacity": "0.5",
|
||||
"d": "M12.9428 4.99993C13.0415 5.09868 13.1232 5.21133 13.1859 5.33327H9.33334V1.48071C9.45528 1.54338 9.56794 1.62504 9.66668 1.72379L12.9428 4.99993Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "FileZip"
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './FileZip.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'FileZip'
|
||||
|
||||
export default Icon
|
|
@ -1,3 +1,4 @@
|
|||
export { default as File05 } from './File05'
|
||||
export { default as FileSearch02 } from './FileSearch02'
|
||||
export { default as FileZip } from './FileZip'
|
||||
export { default as Folder } from './Folder'
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector",
|
||||
"d": "M8 1C4.1325 1 1 4.1325 1 8C1 11.0975 3.00375 13.7137 5.78625 14.6413C6.13625 14.7025 6.2675 14.4925 6.2675 14.3088C6.2675 14.1425 6.25875 13.5913 6.25875 13.005C4.5 13.3288 4.045 12.5763 3.905 12.1825C3.82625 11.9812 3.485 11.36 3.1875 11.1937C2.9425 11.0625 2.5925 10.7387 3.17875 10.73C3.73 10.7212 4.12375 11.2375 4.255 11.4475C4.885 12.5062 5.89125 12.2088 6.29375 12.025C6.355 11.57 6.53875 11.2638 6.74 11.0887C5.1825 10.9137 3.555 10.31 3.555 7.6325C3.555 6.87125 3.82625 6.24125 4.2725 5.75125C4.2025 5.57625 3.9575 4.85875 4.3425 3.89625C4.3425 3.89625 4.92875 3.7125 6.2675 4.61375C6.8275 4.45625 7.4225 4.3775 8.0175 4.3775C8.6125 4.3775 9.2075 4.45625 9.7675 4.61375C11.1063 3.70375 11.6925 3.89625 11.6925 3.89625C12.0775 4.85875 11.8325 5.57625 11.7625 5.75125C12.2087 6.24125 12.48 6.8625 12.48 7.6325C12.48 10.3187 10.8438 10.9137 9.28625 11.0887C9.54 11.3075 9.75875 11.7275 9.75875 12.3837C9.75875 13.32 9.75 14.0725 9.75 14.3088C9.75 14.4925 9.88125 14.7113 10.2312 14.6413C11.6209 14.1721 12.8284 13.279 13.6839 12.0877C14.5393 10.8963 14.9996 9.46668 15 8C15 4.1325 11.8675 1 8 1Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Github"
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Github.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Github'
|
||||
|
||||
export default Icon
|
|
@ -5,6 +5,7 @@ export { default as Download02 } from './Download02'
|
|||
export { default as Edit03 } from './Edit03'
|
||||
export { default as Edit04 } from './Edit04'
|
||||
export { default as Eye } from './Eye'
|
||||
export { default as Github } from './Github'
|
||||
export { default as MessageClockCircle } from './MessageClockCircle'
|
||||
export { default as PlusCircle } from './PlusCircle'
|
||||
export { default as QuestionTriangle } from './QuestionTriangle'
|
||||
|
|
|
@ -1,64 +1,81 @@
|
|||
import type { FC } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
import Badge, { BadgeState } from '@/app/components/base/badge/index'
|
||||
type Option = {
|
||||
value: string
|
||||
text: string
|
||||
}
|
||||
|
||||
type TabSliderProps = {
|
||||
className?: string
|
||||
itemWidth?: number
|
||||
value: string
|
||||
onChange: (v: string) => void
|
||||
options: Option[]
|
||||
}
|
||||
|
||||
const TabSlider: FC<TabSliderProps> = ({
|
||||
className,
|
||||
itemWidth = 118,
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
}) => {
|
||||
const currentIndex = options.findIndex(option => option.value === value)
|
||||
const current = options[currentIndex]
|
||||
const [activeIndex, setActiveIndex] = useState(options.findIndex(option => option.value === value))
|
||||
const [sliderStyle, setSliderStyle] = useState({})
|
||||
|
||||
const updateSliderStyle = (index: number) => {
|
||||
const tabElement = document.getElementById(`tab-${index}`)
|
||||
if (tabElement) {
|
||||
const { offsetLeft, offsetWidth } = tabElement
|
||||
setSliderStyle({
|
||||
transform: `translateX(${offsetLeft}px)`,
|
||||
width: `${offsetWidth}px`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const newIndex = options.findIndex(option => option.value === value)
|
||||
setActiveIndex(newIndex)
|
||||
updateSliderStyle(newIndex)
|
||||
}, [value, options])
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'relative flex p-0.5 rounded-lg bg-gray-200')}>
|
||||
{
|
||||
options.map((option, index) => (
|
||||
<div
|
||||
key={option.value}
|
||||
className={`
|
||||
flex justify-center items-center h-7 text-[13px]
|
||||
font-semibold text-gray-600 rounded-[7px] cursor-pointer
|
||||
hover:bg-gray-50
|
||||
${index !== options.length - 1 && 'mr-[1px]'}
|
||||
`}
|
||||
style={{
|
||||
width: itemWidth,
|
||||
}}
|
||||
onClick={() => onChange(option.value)}
|
||||
>
|
||||
{option.text}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{
|
||||
current && (
|
||||
<div
|
||||
className={`
|
||||
absolute flex justify-center items-center h-7 bg-white text-[13px] font-semibold text-primary-600
|
||||
border-[0.5px] border-gray-200 rounded-[7px] shadow-xs transition-transform
|
||||
`}
|
||||
style={{
|
||||
width: itemWidth,
|
||||
transform: `translateX(${currentIndex * itemWidth + 1}px)`,
|
||||
}}
|
||||
>
|
||||
{current.text}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className={cn(className, 'inline-flex p-0.5 rounded-[10px] bg-components-segmented-control-bg-normal relative items-center justify-center')}>
|
||||
<div
|
||||
className="absolute top-0.5 bottom-0.5 left-0 right-0 bg-components-panel-bg rounded-[10px] transition-transform duration-300 ease-in-out shadows-shadow-xs"
|
||||
style={sliderStyle}
|
||||
/>
|
||||
{options.map((option, index) => (
|
||||
<div
|
||||
id={`tab-${index}`}
|
||||
key={option.value}
|
||||
className={cn(
|
||||
'relative flex justify-center items-center px-2.5 py-1.5 gap-1 rounded-[10px] transition-colors duration-300 ease-in-out cursor-pointer z-10',
|
||||
'system-md-semibold',
|
||||
index === activeIndex
|
||||
? 'text-text-primary'
|
||||
: 'text-text-tertiary',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (index !== activeIndex) {
|
||||
onChange(option.value)
|
||||
updateSliderStyle(index)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{option.text}
|
||||
{option.value === 'plugins'
|
||||
&& <Badge
|
||||
size='s'
|
||||
uppercase={true}
|
||||
state={BadgeState.Default}
|
||||
>
|
||||
6
|
||||
</Badge>
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import AccountDropdown from './account-dropdown'
|
|||
import AppNav from './app-nav'
|
||||
import DatasetNav from './dataset-nav'
|
||||
import EnvNav from './env-nav'
|
||||
import PluginsNav from './plugins-nav'
|
||||
import ExploreNav from './explore-nav'
|
||||
import ToolsNav from './tools-nav'
|
||||
import GithubStar from './github-star'
|
||||
|
@ -59,6 +60,11 @@ const Header = () => {
|
|||
<Link href="/apps" className='flex items-center mr-4'>
|
||||
<LogoSite className='object-contain' />
|
||||
</Link>
|
||||
{enableBilling && (
|
||||
<div className='select-none'>
|
||||
<HeaderBillingBtn onClick={handlePlanClick} />
|
||||
</div>
|
||||
)}
|
||||
<GithubStar />
|
||||
</>}
|
||||
</div>
|
||||
|
@ -67,6 +73,11 @@ const Header = () => {
|
|||
<Link href="/apps" className='flex items-center mr-4'>
|
||||
<LogoSite />
|
||||
</Link>
|
||||
{enableBilling && (
|
||||
<div className='select-none'>
|
||||
<HeaderBillingBtn onClick={handlePlanClick} />
|
||||
</div>
|
||||
)}
|
||||
<GithubStar />
|
||||
</div>
|
||||
)}
|
||||
|
@ -80,11 +91,9 @@ const Header = () => {
|
|||
)}
|
||||
<div className='flex items-center flex-shrink-0'>
|
||||
<EnvNav />
|
||||
{enableBilling && (
|
||||
<div className='mr-3 select-none'>
|
||||
<HeaderBillingBtn onClick={handlePlanClick} />
|
||||
</div>
|
||||
)}
|
||||
<div className='mr-3'>
|
||||
<PluginsNav />
|
||||
</div>
|
||||
<WorkspaceProvider>
|
||||
<AccountDropdown isMobile={isMobile} />
|
||||
</WorkspaceProvider>
|
||||
|
|
30
web/app/components/header/plugins-nav/index.tsx
Normal file
30
web/app/components/header/plugins-nav/index.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
'use client'
|
||||
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Link from 'next/link'
|
||||
import classNames from '@/utils/classnames'
|
||||
import { Group } from '@/app/components/base/icons/src/vender/other'
|
||||
type PluginsNavProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const PluginsNav = ({
|
||||
className,
|
||||
}: PluginsNavProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Link href="/plugins" className={classNames(
|
||||
className, 'group',
|
||||
)}>
|
||||
<div className='flex flex-row p-1.5 gap-0.5 items-center justify-center rounded-xl system-xs-medium-uppercase hover:bg-state-base-hover text-text-tertiary hover:text-text-secondary'>
|
||||
<div className='flex w-4 h-4 justify-center items-center'>
|
||||
<Group />
|
||||
</div>
|
||||
<span className='px-0.5'>{t('common.menus.plugins')}</span>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default PluginsNav
|
5
web/i18n/en-US/marketplace.ts
Normal file
5
web/i18n/en-US/marketplace.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
const translation = {
|
||||
|
||||
}
|
||||
|
||||
export default translation
|
0
web/service/plugins.ts
Normal file
0
web/service/plugins.ts
Normal file
Loading…
Reference in New Issue
Block a user