update page header

This commit is contained in:
Yi 2024-09-18 18:32:33 +08:00
parent d7d7281c93
commit 792595a46f
11 changed files with 97 additions and 69 deletions

View File

@ -35,8 +35,11 @@ const Container = () => {
const containerRef = useRef<HTMLDivElement>(null) const containerRef = useRef<HTMLDivElement>(null)
return ( return (
<div ref={containerRef} className='grow relative flex flex-col rounded-t-xl bg-components-panel-bg border-t <div
border-divider-subtle overflow-y-auto'> 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 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 justify-between items-center w-full'>
<div className='flex-1'> <div className='flex-1'>
@ -96,12 +99,15 @@ const Container = () => {
</div> </div>
</div> </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='flex flex-col 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='h-px self-stretch bg-divider-subtle'></div>
<div className='flex items-center gap-2 self-stretch'> <div className='flex items-center gap-2 self-stretch'>
{/* Content for active tab will go here */} {/* Filter goes here */}
</div> </div>
</div> </div>
<div className='flex px-12 items-start content-start gap-2 flex-grow self-stretch flex-wrap'>
{/* Plugin cards go here */}
</div>
<div className='flex items-center justify-center py-4 gap-2 text-text-quaternary'> <div className='flex items-center justify-center py-4 gap-2 text-text-quaternary'>
<RiDragDropLine className='w-4 h-4' /> <RiDragDropLine className='w-4 h-4' />
<span className='system-xs-regular'>Drop plugin package here to install</span> <span className='system-xs-regular'>Drop plugin package here to install</span>

View File

@ -1,7 +1,6 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import classNames from '@/utils/classnames' import classNames from '@/utils/classnames'
import { useSelector } from '@/context/app-context'
type LogoSiteProps = { type LogoSiteProps = {
className?: string className?: string
@ -10,17 +9,10 @@ type LogoSiteProps = {
const LogoSite: FC<LogoSiteProps> = ({ const LogoSite: FC<LogoSiteProps> = ({
className, className,
}) => { }) => {
const { theme } = useSelector((s) => {
return {
theme: s.theme,
}
})
const src = theme === 'light' ? '/logo/logo-site.png' : `/logo/logo-site-${theme}.png`
return ( return (
<img <img
src={src} src={'/logo/logo.png'}
className={classNames('block w-auto h-10', className)} className={classNames('block w-[22.651px] h-[24.5px]', className)}
alt='logo' alt='logo'
/> />
) )

View File

@ -7,11 +7,13 @@ import cn from '@/utils/classnames'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
type Props = { type Props = {
onClick: () => void onClick?: () => void
isDisplayOnly?: boolean
} }
const HeaderBillingBtn: FC<Props> = ({ const HeaderBillingBtn: FC<Props> = ({
onClick, onClick,
isDisplayOnly = false,
}) => { }) => {
const { plan, enableBilling, isFetchedPlan } = useProviderContext() const { plan, enableBilling, isFetchedPlan } = useProviderContext()
const { const {
@ -25,9 +27,9 @@ const HeaderBillingBtn: FC<Props> = ({
})() })()
const classNames = (() => { const classNames = (() => {
if (type === Plan.professional) if (type === Plan.professional)
return 'border-[#E0F2FE] hover:border-[#B9E6FE] bg-[#E0F2FE] text-[#026AA2]' return `border-[#E0F2FE] ${!isDisplayOnly ? 'hover:border-[#B9E6FE]' : ''} bg-[#E0F2FE] text-[#026AA2]`
if (type === Plan.team) if (type === Plan.team)
return 'border-[#E0EAFF] hover:border-[#C7D7FE] bg-[#E0EAFF] text-[#3538CD]' return `border-[#E0EAFF] ${!isDisplayOnly ? 'hover:border-[#C7D7FE]' : ''} bg-[#E0EAFF] text-[#3538CD]`
return '' return ''
})() })()
@ -35,10 +37,22 @@ const HeaderBillingBtn: FC<Props> = ({
return null return null
if (type === Plan.sandbox) if (type === Plan.sandbox)
return <UpgradeBtn onClick={onClick} isShort /> return <UpgradeBtn onClick={isDisplayOnly ? undefined : onClick} isShort />
const handleClick = () => {
if (!isDisplayOnly && onClick)
onClick()
}
return ( return (
<div onClick={onClick} className={cn(classNames, 'flex items-center h-[22px] px-2 rounded-md border text-xs font-semibold uppercase cursor-pointer')}> <div
onClick={handleClick}
className={cn(
classNames,
'flex items-center h-[22px] px-2 rounded-md border text-xs font-semibold uppercase',
isDisplayOnly ? 'cursor-default' : 'cursor-pointer',
)}
>
{name} {name}
</div> </div>
) )

View File

@ -9,7 +9,6 @@ import { Menu, Transition } from '@headlessui/react'
import Indicator from '../indicator' import Indicator from '../indicator'
import AccountAbout from '../account-about' import AccountAbout from '../account-about'
import { mailToSupport } from '../utils/util' import { mailToSupport } from '../utils/util'
import WorkplaceSelector from './workplace-selector'
import classNames from '@/utils/classnames' import classNames from '@/utils/classnames'
import I18n from '@/context/i18n' import I18n from '@/context/i18n'
import Avatar from '@/app/components/base/avatar' import Avatar from '@/app/components/base/avatar'
@ -101,10 +100,6 @@ export default function AppSelector({ isMobile }: IAppSelector) {
</div> </div>
</div> </div>
</Menu.Item> </Menu.Item>
<div className='px-1 py-1'>
<div className='mt-2 px-3 text-xs font-medium text-gray-500'>{t('common.userProfile.workspace')}</div>
<WorkplaceSelector />
</div>
<div className="px-1 py-1"> <div className="px-1 py-1">
<Menu.Item> <Menu.Item>
<div className={itemClassName} onClick={() => setShowAccountSettingModal({ payload: 'account' })}> <div className={itemClassName} onClick={() => setShowAccountSettingModal({ payload: 'account' })}>

View File

@ -2,33 +2,20 @@ import { Fragment } from 'react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Menu, Transition } from '@headlessui/react' import { Menu, Transition } from '@headlessui/react'
import s from './index.module.css' import { RiArrowDownSLine } from '@remixicon/react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { switchWorkspace } from '@/service/common' import { switchWorkspace } from '@/service/common'
import { useWorkspacesContext } from '@/context/workspace-context' import { useWorkspacesContext } from '@/context/workspace-context'
import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows' import HeaderBillingBtn from '@/app/components/billing/header-billing-btn'
import { Check } from '@/app/components/base/icons/src/vender/line/general' import { useProviderContext } from '@/context/provider-context'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
const itemClassName = `
flex items-center px-3 py-2 h-10 cursor-pointer
`
const itemIconClassName = `
shrink-0 mr-2 flex items-center justify-center w-6 h-6 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600
`
const itemNameClassName = `
grow mr-2 text-sm text-gray-700 text-left
`
const itemCheckClassName = `
shrink-0 w-4 h-4 text-primary-600
`
const WorkplaceSelector = () => { const WorkplaceSelector = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { notify } = useContext(ToastContext) const { notify } = useContext(ToastContext)
const { workspaces } = useWorkspacesContext() const { workspaces } = useWorkspacesContext()
const { enableBilling } = useProviderContext()
const currentWorkspace = workspaces.find(v => v.current) const currentWorkspace = workspaces.find(v => v.current)
const handleSwitchWorkspace = async (tenant_id: string) => { const handleSwitchWorkspace = async (tenant_id: string) => {
try { try {
if (currentWorkspace?.id === tenant_id) if (currentWorkspace?.id === tenant_id)
@ -49,13 +36,13 @@ const WorkplaceSelector = () => {
<> <>
<Menu.Button className={cn( <Menu.Button className={cn(
` `
${itemClassName} w-full flex items-center p-0.5 gap-1.5 w-full
group hover:bg-gray-50 cursor-pointer ${open && 'bg-gray-50'} rounded-lg group hover:bg-state-base-hover cursor-pointer ${open && 'bg-state-base-hover'} rounded-[10px]
`, `,
)}> )}>
<div className={itemIconClassName}>{currentWorkspace?.name[0].toLocaleUpperCase()}</div> <div className='flex items-center justify-center w-7 h-7 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600'>{currentWorkspace?.name[0].toLocaleUpperCase()}</div>
<div className={`${itemNameClassName} truncate`}>{currentWorkspace?.name}</div> <div className={'truncate max-w-[80px] line-clamp-1 overflow-hidden text-text-secondary text-ellipsis system-sm-medium'}>{currentWorkspace?.name}</div>
<ChevronRight className='shrink-0 w-[14px] h-[14px] text-gray-500' /> <RiArrowDownSLine className='w-4 h-4 text-text-secondary' />
</Menu.Button> </Menu.Button>
<Transition <Transition
as={Fragment} as={Fragment}
@ -69,19 +56,24 @@ const WorkplaceSelector = () => {
<Menu.Items <Menu.Items
className={cn( className={cn(
` `
absolute top-[1px] min-w-[200px] max-h-[70vh] overflow-y-scroll z-10 bg-white border-[0.5px] border-gray-200 flex w-[280px] flex-col items-start absolute left-[-15px] mt-1 rounded-xl shadows-shadow-lg
divide-y divide-gray-100 origin-top-right rounded-xl
`, `,
s.popup,
)} )}
> >
<div className="px-1 py-1"> <div className="flex flex-col p-1 pb-2 items-start self-stretch w-full rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadows-shadow-lg ">
<div className='flex px-3 pt-1 pb-0.5 items-start self-stretch'>
<span className='flex-1 text-text-tertiary system-xs-medium-uppercase'>{t('common.userProfile.workspace')}</span>
</div>
{ {
workspaces.map(workspace => ( workspaces.map(workspace => (
<div className={itemClassName} key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}> <div className='flex py-1 pl-3 pr-2 items-center gap-2 self-stretch hover:bg-state-base-hover rounded-lg' key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
<div className={itemIconClassName}>{workspace.name[0].toLocaleUpperCase()}</div> <div className='flex items-center justify-center w-7 h-7 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600'>{workspace.name[0].toLocaleUpperCase()}</div>
<div className={itemNameClassName}>{workspace.name}</div> <div className='line-clamp-1 flex-grow overflow-hidden text-text-secondary text-ellipsis system-md-regular'>{workspace.name}</div>
{workspace.current && <Check className={itemCheckClassName} />} {enableBilling && (
<div className='select-none'>
<HeaderBillingBtn isDisplayOnly={true} />
</div>
)}
</div> </div>
)) ))
} }

View File

@ -16,6 +16,7 @@ import GithubStar from './github-star'
import { WorkspaceProvider } from '@/context/workspace-context' import { WorkspaceProvider } from '@/context/workspace-context'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
import LogoSite from '@/app/components/base/logo/logo-site' import LogoSite from '@/app/components/base/logo/logo-site'
import WorkplaceSelector from '@/app/components/header/account-dropdown/workplace-selector'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { useModalContext } from '@/context/modal-context' import { useModalContext } from '@/context/modal-context'
@ -48,7 +49,7 @@ const Header = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedSegment]) }, [selectedSegment])
return ( return (
<div className='flex flex-1 items-center justify-between px-4'> <div className='flex flex-1 items-center justify-between pr-3'>
<div className='flex items-center'> <div className='flex items-center'>
{isMobile && <div {isMobile && <div
className='flex items-center justify-center h-8 w-8 cursor-pointer' className='flex items-center justify-center h-8 w-8 cursor-pointer'
@ -56,23 +57,31 @@ const Header = () => {
> >
<Bars3Icon className="h-4 w-4 text-gray-500" /> <Bars3Icon className="h-4 w-4 text-gray-500" />
</div>} </div>}
{!isMobile && <> {!isMobile
<Link href="/apps" className='flex items-center mr-4'> && <div className='flex w-64 p-2 pl-3 gap-1.5 items-center shrink-0 self-stretch'>
<Link href="/apps" className='flex w-8 h-8 items-center justify-center gap-2 shrink-0'>
<LogoSite className='object-contain' /> <LogoSite className='object-contain' />
</Link> </Link>
{enableBilling && ( <div className='font-light text-divider-deep'>/</div>
<div className='select-none'> <div className='flex items-center gap-0.5'>
<HeaderBillingBtn onClick={handlePlanClick} /> <WorkspaceProvider>
</div> <WorkplaceSelector />
)} </WorkspaceProvider>
<GithubStar /> {enableBilling && (
</>} <div className='select-none'>
<HeaderBillingBtn onClick={handlePlanClick} />
</div>
)}
</div>
</div>
}
</div> </div>
{isMobile && ( {isMobile && (
<div className='flex'> <div className='flex'>
<Link href="/apps" className='flex items-center mr-4'> <Link href="/apps" className='flex items-center mr-4'>
<LogoSite /> <LogoSite />
</Link> </Link>
<div className='font-light text-divider-deep'>/</div>
{enableBilling && ( {enableBilling && (
<div className='select-none'> <div className='select-none'>
<HeaderBillingBtn onClick={handlePlanClick} /> <HeaderBillingBtn onClick={handlePlanClick} />
@ -94,9 +103,7 @@ const Header = () => {
<div className='mr-3'> <div className='mr-3'>
<PluginsNav /> <PluginsNav />
</div> </div>
<WorkspaceProvider> <AccountDropdown isMobile={isMobile} />
<AccountDropdown isMobile={isMobile} />
</WorkspaceProvider>
</div> </div>
{(isMobile && isShowNavMenu) && ( {(isMobile && isShowNavMenu) && (
<div className='w-full flex flex-col p-2 gap-y-1'> <div className='w-full flex flex-col p-2 gap-y-1'>

View File

@ -68,7 +68,7 @@ const Nav = ({
{ {
curNav && isActivated && ( curNav && isActivated && (
<> <>
<div className='font-light text-gray-300 '>/</div> <div className='font-light text-divider-deep'>/</div>
<NavSelector <NavSelector
isApp={isApp} isApp={isApp}
curNav={curNav} curNav={curNav}

View File

@ -0,0 +1,7 @@
.textGradient {
background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}

View File

@ -1,5 +1,10 @@
const translation = { const translation = {
plugins: {
title: 'Plugins',
},
discover: {
title: 'Explore Marketplace',
},
} }
export default translation export default translation

View File

@ -0,0 +1,10 @@
const translation = {
plugins: {
title: '插件',
},
discover: {
title: '探索市场',
},
}
export default translation

BIN
web/public/logo/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB