Feat/header ssr (#594)

This commit is contained in:
zxhlyh 2023-07-18 16:57:14 +08:00 committed by GitHub
parent b0091452ca
commit 3e1d5ac51b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 916 additions and 275 deletions

View File

@ -3,6 +3,7 @@ import type { ReactNode } from 'react'
import SwrInitor from '@/app/components/swr-initor'
import { AppContextProvider } from '@/context/app-context'
import GA, { GaType } from '@/app/components/base/ga'
import HeaderWrapper from '@/app/components/header/HeaderWrapper'
import Header from '@/app/components/header'
const Layout = ({ children }: { children: ReactNode }) => {
@ -11,7 +12,9 @@ const Layout = ({ children }: { children: ReactNode }) => {
<GA gaType={GaType.admin} />
<SwrInitor>
<AppContextProvider>
<Header />
<HeaderWrapper>
<Header />
</HeaderWrapper>
{children}
</AppContextProvider>
</SwrInitor>

View File

@ -1,39 +1,41 @@
'use client'
import cn from 'classnames'
interface IAvatarProps {
type AvatarProps = {
name: string
avatar?: string
size?: number
className?: string
textClassName?: string
}
const Avatar = ({
name,
avatar,
size = 30,
className
}: IAvatarProps) => {
const avatarClassName = `shrink-0 flex items-center rounded-full bg-primary-600`
const style = { width: `${size}px`, height:`${size}px`, fontSize: `${size}px`, lineHeight: `${size}px` }
className,
textClassName,
}: AvatarProps) => {
const avatarClassName = 'shrink-0 flex items-center rounded-full bg-primary-600'
const style = { width: `${size}px`, height: `${size}px`, fontSize: `${size}px`, lineHeight: `${size}px` }
if (avatar) {
return (
<img
className={cn(avatarClassName, className)}
<img
className={cn(avatarClassName, className)}
style={style}
alt={name}
alt={name}
src={avatar}
/>
)
}
return (
<div
className={cn(avatarClassName, className)}
<div
className={cn(avatarClassName, className)}
style={style}
>
<div
className={`text-center text-white scale-[0.4]`}
<div
className={cn(textClassName, 'text-center text-white scale-[0.4]')}
style={style}
>
{name[0].toLocaleUpperCase()}
@ -42,4 +44,4 @@ const Avatar = ({
)
}
export default Avatar
export default Avatar

View File

@ -0,0 +1,8 @@
<svg width="50" height="26" viewBox="0 0 50 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Dify">
<path d="M6.61784 2.064C8.37784 2.064 9.92184 2.408 11.2498 3.096C12.5938 3.784 13.6258 4.768 14.3458 6.048C15.0818 7.312 15.4498 8.784 15.4498 10.464C15.4498 12.144 15.0818 13.616 14.3458 14.88C13.6258 16.128 12.5938 17.096 11.2498 17.784C9.92184 18.472 8.37784 18.816 6.61784 18.816H0.761841V2.064H6.61784ZM6.49784 15.96C8.25784 15.96 9.61784 15.48 10.5778 14.52C11.5378 13.56 12.0178 12.208 12.0178 10.464C12.0178 8.72 11.5378 7.36 10.5778 6.384C9.61784 5.392 8.25784 4.896 6.49784 4.896H4.12184V15.96H6.49784Z" fill="#1D2939"/>
<path d="M20.869 3.936C20.277 3.936 19.781 3.752 19.381 3.384C18.997 3 18.805 2.528 18.805 1.968C18.805 1.408 18.997 0.944 19.381 0.576C19.781 0.192 20.277 0 20.869 0C21.461 0 21.949 0.192 22.333 0.576C22.733 0.944 22.933 1.408 22.933 1.968C22.933 2.528 22.733 3 22.333 3.384C21.949 3.752 21.461 3.936 20.869 3.936ZM22.525 5.52V18.816H19.165V5.52H22.525Z" fill="#1D2939"/>
<path d="M33.1407 8.28H30.8127V18.816H27.4047V8.28H25.8927V5.52H27.4047V4.848C27.4047 3.216 27.8687 2.016 28.7967 1.248C29.7247 0.48 31.1247 0.12 32.9967 0.168001V3C32.1807 2.984 31.6127 3.12 31.2927 3.408C30.9727 3.696 30.8127 4.216 30.8127 4.968V5.52H33.1407V8.28Z" fill="#1D2939"/>
<path d="M49.2381 5.52L41.0061 25.104H37.4301L40.3101 18.48L34.9821 5.52H38.7501L42.1821 14.808L45.6621 5.52H49.2381Z" fill="#1D2939"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,5 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="github">
<path id="Vector" d="M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92063 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14938 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5987 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z" fill="#24292F"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="arrow-up-right">
<path id="Icon" d="M4.08325 9.91665L9.91659 4.08331M9.91659 4.08331H4.08325M9.91659 4.08331V9.91665" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 319 B

View File

@ -0,0 +1,5 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="chevron-down">
<path id="Icon" d="M3 4.5L6 7.5L9 4.5" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View File

@ -0,0 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="chevron-right">
<path id="Icon" d="M5.25 10.5L8.75 7L5.25 3.5" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 264 B

View File

@ -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="check">
<path id="Icon" d="M13.3334 4L6.00008 11.3333L2.66675 8" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@ -0,0 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="log-out-01">
<path id="Icon" d="M9.33333 9.91667L12.25 7M12.25 7L9.33333 4.08333M12.25 7H5.25M5.25 1.75H4.55C3.56991 1.75 3.07986 1.75 2.70552 1.94074C2.37623 2.10852 2.10852 2.37623 1.94074 2.70552C1.75 3.07986 1.75 3.56991 1.75 4.55V9.45C1.75 10.4301 1.75 10.9201 1.94074 11.2945C2.10852 11.6238 2.37623 11.8915 2.70552 12.0593C3.07986 12.25 3.56991 12.25 4.55 12.25H5.25" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 576 B

View File

@ -0,0 +1,5 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="terminal-square">
<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M8.91927 1H3.08073C2.81716 0.999992 2.58977 0.999984 2.40249 1.01529C2.20481 1.03144 2.00821 1.06709 1.81902 1.16349C1.53677 1.3073 1.3073 1.53677 1.16349 1.81902C1.06709 2.00821 1.03144 2.20481 1.01529 2.40249C0.999984 2.58977 0.999992 2.81714 1 3.08071V8.91927C0.999992 9.18284 0.999984 9.41023 1.01529 9.59752C1.03144 9.79519 1.06709 9.9918 1.16349 10.181C1.3073 10.4632 1.53677 10.6927 1.81902 10.8365C2.00821 10.9329 2.20481 10.9686 2.40249 10.9847C2.58977 11 2.81715 11 3.08072 11H8.91928C9.18285 11 9.41023 11 9.59752 10.9847C9.79519 10.9686 9.9918 10.9329 10.181 10.8365C10.4632 10.6927 10.6927 10.4632 10.8365 10.181C10.9329 9.9918 10.9686 9.79519 10.9847 9.59752C11 9.41023 11 9.18285 11 8.91928V3.08072C11 2.81715 11 2.58977 10.9847 2.40249C10.9686 2.20481 10.9329 2.00821 10.8365 1.81902C10.6927 1.53677 10.4632 1.3073 10.181 1.16349C9.9918 1.06709 9.79519 1.03144 9.59752 1.01529C9.41023 0.999984 9.18284 0.999992 8.91927 1ZM3.85355 4.14645C3.65829 3.95118 3.34171 3.95118 3.14645 4.14645C2.95118 4.34171 2.95118 4.65829 3.14645 4.85355L4.29289 6L3.14645 7.14645C2.95118 7.34171 2.95118 7.65829 3.14645 7.85355C3.34171 8.04882 3.65829 8.04882 3.85355 7.85355L5.35355 6.35355C5.54882 6.15829 5.54882 5.84171 5.35355 5.64645L3.85355 4.14645ZM6.5 7C6.22386 7 6 7.22386 6 7.5C6 7.77614 6.22386 8 6.5 8H8.5C8.77614 8 9 7.77614 9 7.5C9 7.22386 8.77614 7 8.5 7H6.5Z" fill="#B54708"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,5 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="beaker-02">
<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z" fill="#0E7090"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,62 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "50",
"height": "26",
"viewBox": "0 0 50 26",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "Dify"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M6.61784 2.064C8.37784 2.064 9.92184 2.408 11.2498 3.096C12.5938 3.784 13.6258 4.768 14.3458 6.048C15.0818 7.312 15.4498 8.784 15.4498 10.464C15.4498 12.144 15.0818 13.616 14.3458 14.88C13.6258 16.128 12.5938 17.096 11.2498 17.784C9.92184 18.472 8.37784 18.816 6.61784 18.816H0.761841V2.064H6.61784ZM6.49784 15.96C8.25784 15.96 9.61784 15.48 10.5778 14.52C11.5378 13.56 12.0178 12.208 12.0178 10.464C12.0178 8.72 11.5378 7.36 10.5778 6.384C9.61784 5.392 8.25784 4.896 6.49784 4.896H4.12184V15.96H6.49784Z",
"fill": "#1D2939"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M20.869 3.936C20.277 3.936 19.781 3.752 19.381 3.384C18.997 3 18.805 2.528 18.805 1.968C18.805 1.408 18.997 0.944 19.381 0.576C19.781 0.192 20.277 0 20.869 0C21.461 0 21.949 0.192 22.333 0.576C22.733 0.944 22.933 1.408 22.933 1.968C22.933 2.528 22.733 3 22.333 3.384C21.949 3.752 21.461 3.936 20.869 3.936ZM22.525 5.52V18.816H19.165V5.52H22.525Z",
"fill": "#1D2939"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M33.1407 8.28H30.8127V18.816H27.4047V8.28H25.8927V5.52H27.4047V4.848C27.4047 3.216 27.8687 2.016 28.7967 1.248C29.7247 0.48 31.1247 0.12 32.9967 0.168001V3C32.1807 2.984 31.6127 3.12 31.2927 3.408C30.9727 3.696 30.8127 4.216 30.8127 4.968V5.52H33.1407V8.28Z",
"fill": "#1D2939"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M49.2381 5.52L41.0061 25.104H37.4301L40.3101 18.48L34.9821 5.52H38.7501L42.1821 14.808L45.6621 5.52H49.2381Z",
"fill": "#1D2939"
},
"children": []
}
]
}
]
},
"name": "Dify"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Dify.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} />)
export default Icon

View File

@ -0,0 +1,36 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "18",
"height": "18",
"viewBox": "0 0 18 18",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "github"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Vector",
"d": "M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92063 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14938 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5987 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z",
"fill": "#24292F"
},
"children": []
}
]
}
]
},
"name": "Github"
}

View File

@ -0,0 +1,14 @@
// 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} />)
export default Icon

View File

@ -0,0 +1,2 @@
export { default as Dify } from './Dify'
export { default as Github } from './Github'

View File

@ -0,0 +1,39 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "14",
"height": "14",
"viewBox": "0 0 14 14",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "arrow-up-right"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M4.08325 9.91665L9.91659 4.08331M9.91659 4.08331H4.08325M9.91659 4.08331V9.91665",
"stroke": "currentColor",
"stroke-width": "1.25",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "ArrowUpRight"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ArrowUpRight.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} />)
export default Icon

View File

@ -0,0 +1,39 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "chevron-down"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M3 4.5L6 7.5L9 4.5",
"stroke": "currentColor",
"stroke-width": "1.5",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "ChevronDown"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ChevronDown.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} />)
export default Icon

View File

@ -0,0 +1,39 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "14",
"height": "14",
"viewBox": "0 0 14 14",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "chevron-right"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M5.25 10.5L8.75 7L5.25 3.5",
"stroke": "currentColor",
"stroke-width": "1.25",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "ChevronRight"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ChevronRight.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} />)
export default Icon

View File

@ -1,2 +1,5 @@
export { default as ArrowNarrowLeft } from './ArrowNarrowLeft'
export { default as ArrowUpRight } from './ArrowUpRight'
export { default as ChevronDown } from './ChevronDown'
export { default as ChevronRight } from './ChevronRight'
export { default as RefreshCw05 } from './RefreshCw05'

View File

@ -0,0 +1,39 @@
{
"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": "check"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M13.3334 4L6.00008 11.3333L2.66675 8",
"stroke": "currentColor",
"stroke-width": "1.5",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "Check"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Check.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} />)
export default Icon

View File

@ -0,0 +1,39 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "14",
"height": "14",
"viewBox": "0 0 14 14",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "log-out-01"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M9.33333 9.91667L12.25 7M12.25 7L9.33333 4.08333M12.25 7H5.25M5.25 1.75H4.55C3.56991 1.75 3.07986 1.75 2.70552 1.94074C2.37623 2.10852 2.10852 2.37623 1.94074 2.70552C1.75 3.07986 1.75 3.56991 1.75 4.55V9.45C1.75 10.4301 1.75 10.9201 1.94074 11.2945C2.10852 11.6238 2.37623 11.8915 2.70552 12.0593C3.07986 12.25 3.56991 12.25 4.55 12.25H5.25",
"stroke": "currentColor",
"stroke-width": "1.25",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "LogOut01"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './LogOut01.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} />)
export default Icon

View File

@ -1,4 +1,6 @@
export { default as Check } from './Check'
export { default as Loading02 } from './Loading02'
export { default as LogOut01 } from './LogOut01'
export { default as Trash03 } from './Trash03'
export { default as XClose } from './XClose'
export { default as X } from './X'

View File

@ -0,0 +1,38 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "terminal-square"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Solid",
"fill-rule": "evenodd",
"clip-rule": "evenodd",
"d": "M8.91927 1H3.08073C2.81716 0.999992 2.58977 0.999984 2.40249 1.01529C2.20481 1.03144 2.00821 1.06709 1.81902 1.16349C1.53677 1.3073 1.3073 1.53677 1.16349 1.81902C1.06709 2.00821 1.03144 2.20481 1.01529 2.40249C0.999984 2.58977 0.999992 2.81714 1 3.08071V8.91927C0.999992 9.18284 0.999984 9.41023 1.01529 9.59752C1.03144 9.79519 1.06709 9.9918 1.16349 10.181C1.3073 10.4632 1.53677 10.6927 1.81902 10.8365C2.00821 10.9329 2.20481 10.9686 2.40249 10.9847C2.58977 11 2.81715 11 3.08072 11H8.91928C9.18285 11 9.41023 11 9.59752 10.9847C9.79519 10.9686 9.9918 10.9329 10.181 10.8365C10.4632 10.6927 10.6927 10.4632 10.8365 10.181C10.9329 9.9918 10.9686 9.79519 10.9847 9.59752C11 9.41023 11 9.18285 11 8.91928V3.08072C11 2.81715 11 2.58977 10.9847 2.40249C10.9686 2.20481 10.9329 2.00821 10.8365 1.81902C10.6927 1.53677 10.4632 1.3073 10.181 1.16349C9.9918 1.06709 9.79519 1.03144 9.59752 1.01529C9.41023 0.999984 9.18284 0.999992 8.91927 1ZM3.85355 4.14645C3.65829 3.95118 3.34171 3.95118 3.14645 4.14645C2.95118 4.34171 2.95118 4.65829 3.14645 4.85355L4.29289 6L3.14645 7.14645C2.95118 7.34171 2.95118 7.65829 3.14645 7.85355C3.34171 8.04882 3.65829 8.04882 3.85355 7.85355L5.35355 6.35355C5.54882 6.15829 5.54882 5.84171 5.35355 5.64645L3.85355 4.14645ZM6.5 7C6.22386 7 6 7.22386 6 7.5C6 7.77614 6.22386 8 6.5 8H8.5C8.77614 8 9 7.77614 9 7.5C9 7.22386 8.77614 7 8.5 7H6.5Z",
"fill": "currentColor"
},
"children": []
}
]
}
]
},
"name": "TerminalSquare"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './TerminalSquare.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} />)
export default Icon

View File

@ -2,3 +2,4 @@ export { default as Container } from './Container'
export { default as Database02 } from './Database02'
export { default as Database03 } from './Database03'
export { default as PuzzlePiece01 } from './PuzzlePiece01'
export { default as TerminalSquare } from './TerminalSquare'

View File

@ -0,0 +1,38 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "beaker-02"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Solid",
"fill-rule": "evenodd",
"clip-rule": "evenodd",
"d": "M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z",
"fill": "currentColor"
},
"children": []
}
]
}
]
},
"name": "Beaker02"
}

View File

@ -0,0 +1,14 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Beaker02.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} />)
export default Icon

View File

@ -0,0 +1 @@
export { default as Beaker02 } from './Beaker02'

View File

@ -0,0 +1,34 @@
'use client'
import classNames from 'classnames'
import { usePathname } from 'next/navigation'
import s from './index.module.css'
import { useAppContext } from '@/context/app-context'
type HeaderWrapperProps = {
children: React.ReactNode
}
const HeaderWrapper = ({
children,
}: HeaderWrapperProps) => {
const pathname = usePathname()
const { langeniusVersionInfo } = useAppContext()
const isBordered = ['/apps', '/datasets'].includes(pathname)
return (
<div className={classNames(
'sticky top-0 left-0 right-0 z-20 flex bg-gray-100 grow-0 shrink-0 basis-auto h-14',
s.header,
isBordered ? 'border-b border-gray-200' : '',
)}
>
<div className={classNames(
s[`header-${langeniusVersionInfo.current_env}`],
'flex flex-1 items-center justify-between px-4',
)}>
{children}
</div>
</div>
)
}
export default HeaderWrapper

View File

@ -1,7 +1,7 @@
.logo-icon {
background: url(../assets/logo-icon.png) center center no-repeat;
background-size: 32px;
box-shadow: 0px 4px 6px -1px rgba(0, 0, 0, 0.05), 0px 2px 4px -2px rgba(0, 0, 0, 0.05);
box-shadow: 0px 2px 4px -2px rgba(0, 0, 0, 0.05), 0px 4px 6px -1px rgba(0, 0, 0, 0.05);
}
.logo-text {

View File

@ -1,10 +1,11 @@
'use client'
import { useTranslation } from 'react-i18next'
import { XMarkIcon } from '@heroicons/react/24/outline'
import classNames from 'classnames'
import Link from 'next/link'
import s from './index.module.css'
import Modal from '@/app/components/base/modal'
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
import { Dify } from '@/app/components/base/icons/src/public/common'
import type { LangGeniusVersionResponse } from '@/models/common'
import { IS_CE_EDITION } from '@/config'
@ -30,16 +31,15 @@ export default function AccountAbout({
className={s.modal}
>
<div className='relative'>
<XMarkIcon className='absolute top-0 -right-2 w-4 h-4 cursor-pointer' onClick={onCancel} />
<div className='absolute -top-2 -right-4 flex justify-center items-center w-8 h-8 cursor-pointer' onClick={onCancel}>
<XClose className='w-4 h-4 text-gray-500' />
</div>
<div>
<div className={classNames(
s['logo-icon'],
'mx-auto mb-3 w-12 h-12 bg-white rounded-xl border border-gray-200',
)} />
<div className={classNames(
s['logo-text'],
'mx-auto mb-2',
'mx-auto mb-3 w-12 h-12 bg-white rounded-xl border-[0.5px] border-gray-200',
)} />
<Dify className='mx-auto mb-2' />
<div className='mb-3 text-center text-xs font-normal text-gray-500'>Version {langeniusVersionInfo?.current_version}</div>
<div className='mb-4 text-center text-xs font-normal text-gray-700'>
<div>© 2023 LangGenius, Inc., Contributors.</div>
@ -55,7 +55,7 @@ export default function AccountAbout({
</div>
</div>
</div>
<div className='mb-4 h-0 border-[0.5px] border-gray-200' />
<div className='mb-4 -mx-8 h-[0.5px] bg-gray-200' />
<div className='flex justify-between items-center'>
<div className='text-xs font-medium text-gray-800'>
{

View File

@ -5,26 +5,22 @@ import { useRouter } from 'next/navigation'
import { useContext } from 'use-context-selector'
import classNames from 'classnames'
import Link from 'next/link'
import { ArrowRightOnRectangleIcon, ArrowTopRightOnSquareIcon, ChevronDownIcon } from '@heroicons/react/24/solid'
import { Menu, Transition } from '@headlessui/react'
import Indicator from '../indicator'
import AccountSetting from '../account-setting'
import AccountAbout from '../account-about'
import WorkplaceSelector from './workplace-selector'
import type { LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
import I18n from '@/context/i18n'
import Avatar from '@/app/components/base/avatar'
import { logout } from '@/service/common'
import { useAppContext } from '@/context/app-context'
import { ArrowUpRight, ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
type IAppSelectorProps = {
userProfile: UserProfileResponse
langeniusVersionInfo: LangGeniusVersionResponse
}
export default function AppSelector({ userProfile, langeniusVersionInfo }: IAppSelectorProps) {
export default function AppSelector() {
const itemClassName = `
flex items-center w-full h-10 px-3 text-gray-700 text-[14px]
rounded-lg font-normal hover:bg-gray-100 cursor-pointer
flex items-center w-full h-9 px-3 text-gray-700 text-[14px]
rounded-lg font-normal hover:bg-gray-50 cursor-pointer
`
const router = useRouter()
const [settingVisible, setSettingVisible] = useState(false)
@ -32,6 +28,7 @@ export default function AppSelector({ userProfile, langeniusVersionInfo }: IAppS
const { locale } = useContext(I18n)
const { t } = useTranslation()
const { userProfile, langeniusVersionInfo } = useAppContext()
const handleLogout = async () => {
await logout({
@ -44,90 +41,94 @@ export default function AppSelector({ userProfile, langeniusVersionInfo }: IAppS
return (
<div className="">
<Menu as="div" className="relative inline-block text-left">
<div>
<Menu.Button
className="
inline-flex items-center h-[38px]
rounded-xl pl-2 pr-2.5 text-[14px] font-normal
text-gray-800 hover:bg-gray-200
"
>
<Avatar name={userProfile.name} className='mr-2' />
{userProfile.name}
<ChevronDownIcon
className="w-3 h-3 ml-1"
aria-hidden="true"
/>
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="
absolute right-0 mt-1.5 w-60 max-w-80
divide-y divide-gray-100 origin-top-right rounded-lg bg-white
shadow-[0_10px_15px_-3px_rgba(0,0,0,0.1),0_4px_6px_rgba(0,0,0,0.05)]
"
>
<Menu.Item>
<div className='flex flex-nowrap items-center px-4 py-[13px]'>
<Avatar name={userProfile.name} size={36} className='mr-3' />
<div className='grow'>
<div className='leading-5 font-normal text-[14px] text-gray-800 break-all'>{userProfile.name}</div>
<div className='leading-[18px] text-xs font-normal text-gray-500 break-all'>{userProfile.email}</div>
</div>
</div>
</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">
<Menu.Item>
<div className={itemClassName} onClick={() => setSettingVisible(true)}>
<div>{t('common.userProfile.settings')}</div>
</div>
</Menu.Item>
<Menu.Item>
<Link
className={classNames(itemClassName, 'group justify-between')}
href={
locale === 'zh-Hans' ? 'https://docs.dify.ai/v/zh-hans/' : 'https://docs.dify.ai/'
}
target='_blank'>
<div>{t('common.userProfile.helpCenter')}</div>
<ArrowTopRightOnSquareIcon className='hidden w-4 h-4 group-hover:flex' />
</Link>
</Menu.Item>
<Menu.Item>
<div className={classNames(itemClassName, 'justify-between')} onClick={() => setAboutVisible(true)}>
<div>{t('common.userProfile.about')}</div>
<div className='flex items-center'>
<div className='mr-2 text-xs font-normal text-gray-500'>{langeniusVersionInfo.current_version}</div>
<Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} />
</div>
</div>
</Menu.Item>
</div>
<Menu.Item>
<div className='p-1' onClick={() => handleLogout()}>
<div
className='flex items-center justify-between h-12 px-3 rounded-lg cursor-pointer group hover:bg-gray-100'
{
({ open }) => (
<>
<div>
<Menu.Button
className={`
inline-flex items-center
rounded-[20px] py-1 pr-2.5 pl-1 text-sm
text-gray-700 hover:bg-gray-200
${open && 'bg-gray-200'}
`}
>
<div className='font-normal text-[14px] text-gray-700'>{t('common.userProfile.logout')}</div>
<ArrowRightOnRectangleIcon className='hidden w-4 h-4 group-hover:flex' />
</div>
<Avatar name={userProfile.name} className='mr-2' size={32} />
{userProfile.name}
<ChevronDown className="w-3 h-3 ml-1 text-gray-700"/>
</Menu.Button>
</div>
</Menu.Item>
</Menu.Items>
</Transition>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="
absolute right-0 mt-1.5 w-60 max-w-80
divide-y divide-gray-100 origin-top-right rounded-lg bg-white
shadow-[0_10px_15px_-3px_rgba(0,0,0,0.1),0_4px_6px_rgba(0,0,0,0.05)]
"
>
<Menu.Item>
<div className='flex flex-nowrap items-center px-4 py-[13px]'>
<Avatar name={userProfile.name} size={36} className='mr-3' />
<div className='grow'>
<div className='leading-5 font-normal text-[14px] text-gray-800 break-all'>{userProfile.name}</div>
<div className='leading-[18px] text-xs font-normal text-gray-500 break-all'>{userProfile.email}</div>
</div>
</div>
</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">
<Menu.Item>
<div className={itemClassName} onClick={() => setSettingVisible(true)}>
<div>{t('common.userProfile.settings')}</div>
</div>
</Menu.Item>
<Menu.Item>
<Link
className={classNames(itemClassName, 'group justify-between')}
href={
locale === 'zh-Hans' ? 'https://docs.dify.ai/v/zh-hans/' : 'https://docs.dify.ai/'
}
target='_blank'>
<div>{t('common.userProfile.helpCenter')}</div>
<ArrowUpRight className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' />
</Link>
</Menu.Item>
<Menu.Item>
<div className={classNames(itemClassName, 'justify-between')} onClick={() => setAboutVisible(true)}>
<div>{t('common.userProfile.about')}</div>
<div className='flex items-center'>
<div className='mr-2 text-xs font-normal text-gray-500'>{langeniusVersionInfo.current_version}</div>
<Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} />
</div>
</div>
</Menu.Item>
</div>
<Menu.Item>
<div className='p-1' onClick={() => handleLogout()}>
<div
className='flex items-center justify-between h-9 px-3 rounded-lg cursor-pointer group hover:bg-gray-50'
>
<div className='font-normal text-[14px] text-gray-700'>{t('common.userProfile.logout')}</div>
<LogOut01 className='hidden w-[14px] h-[14px] text-gray-500 group-hover:flex' />
</div>
</div>
</Menu.Item>
</Menu.Items>
</Transition>
</>
)
}
</Menu>
{
settingVisible && <AccountSetting onCancel={() => setSettingVisible(false)} />

View File

@ -1,20 +1,21 @@
import { Fragment } from 'react'
import { switchWorkspace } from '@/service/common'
import { Menu, Transition } from '@headlessui/react'
import { ChevronRightIcon, CheckIcon } from '@heroicons/react/24/outline'
import cn from 'classnames'
import s from './index.module.css'
import { useContext } from 'use-context-selector'
import { ToastContext } from '@/app/components/base/toast'
import { useTranslation } from 'react-i18next'
import { useRouter } from 'next/navigation'
import { Menu, Transition } from '@headlessui/react'
import cn from 'classnames'
import s from './index.module.css'
import { switchWorkspace } from '@/service/common'
import { useWorkspacesContext } from '@/context/workspace-context'
import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
import { Check } from '@/app/components/base/icons/src/vender/line/general'
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 w-6 h-6 bg-[#EFF4FF] rounded-md
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
@ -32,12 +33,12 @@ const WorkplaceSelector = () => {
const handleSwitchWorkspace = async (tenant_id: string) => {
try {
await switchWorkspace({ url: `/workspaces/switch`, body: { tenant_id } })
await switchWorkspace({ url: '/workspaces/switch', body: { tenant_id } })
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
router.replace('/apps')
} catch (e) {
}
catch (e) {
notify({ type: 'error', message: t('common.provider.saveFailed') })
} finally {
}
}
@ -49,12 +50,12 @@ const WorkplaceSelector = () => {
<Menu.Button className={cn(
`
${itemClassName} w-full
group hover:bg-gray-50 cursor-pointer ${open && 'bg-gray-50'}
`
group hover:bg-gray-50 cursor-pointer ${open && 'bg-gray-50'} rounded-lg
`,
)}>
<div className={itemIconClassName} />
<div className={itemIconClassName}>{currentWrokspace?.name[0].toLocaleUpperCase()}</div>
<div className={`${itemNameClassName} truncate`}>{currentWrokspace?.name}</div>
<ChevronRightIcon className='shrink-0 w-[14px] h-[14px]' />
<ChevronRight className='shrink-0 w-[14px] h-[14px] text-gray-500' />
</Menu.Button>
<Transition
as={Fragment}
@ -71,16 +72,16 @@ const WorkplaceSelector = () => {
absolute top-[1px] min-w-[200px] z-10 bg-white border-[0.5px] border-gray-200
divide-y divide-gray-100 origin-top-right rounded-xl
`,
s.popup
s.popup,
)}
>
<div className="px-1 py-1">
{
workspaces.map(workspace => (
<div className={itemClassName} key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
<div className={itemIconClassName} />
<div className={itemIconClassName}>{workspace.name[0].toLocaleUpperCase()}</div>
<div className={itemNameClassName}>{workspace.name}</div>
{workspace.current && <CheckIcon className={itemCheckClassName} />}
{workspace.current && <Check className={itemCheckClassName} />}
</div>
))
}
@ -94,4 +95,4 @@ const WorkplaceSelector = () => {
)
}
export default WorkplaceSelector
export default WorkplaceSelector

View File

@ -1,3 +1,5 @@
'use client'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams, usePathname } from 'next/navigation'

View File

@ -1,3 +0,0 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z" fill="#0E7090"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,3 +0,0 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92062 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14937 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5988 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z" fill="#24292F"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,3 +1,5 @@
'use client'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams, useRouter } from 'next/navigation'

View File

@ -0,0 +1,46 @@
'use client'
import { useTranslation } from 'react-i18next'
import { useAppContext } from '@/context/app-context'
import { Beaker02 } from '@/app/components/base/icons/src/vender/solid/education'
import { TerminalSquare } from '@/app/components/base/icons/src/vender/solid/development'
const headerEnvClassName: { [k: string]: string } = {
DEVELOPMENT: 'bg-[#FEC84B] border-[#FDB022] text-[#93370D]',
TESTING: 'bg-[#A5F0FC] border-[#67E3F9] text-[#164C63]',
}
const EnvNav = () => {
const { t } = useTranslation()
const { langeniusVersionInfo } = useAppContext()
const showEnvTag = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT'
if (!showEnvTag)
return null
return (
<div className={`
flex items-center h-[22px] mr-4 rounded-md px-2 text-xs font-medium border
${headerEnvClassName[langeniusVersionInfo.current_env]}
`}>
{
langeniusVersionInfo.current_env === 'TESTING' && (
<>
<Beaker02 className='w-3 h-3 mr-1' />
{t('common.environment.testing')}
</>
)
}
{
langeniusVersionInfo.current_env === 'DEVELOPMENT' && (
<>
<TerminalSquare className='w-3 h-3 mr-1' />
{t('common.environment.development')}
</>
)
}
</div>
)
}
export default EnvNav

View File

@ -0,0 +1,37 @@
'use client'
import { useTranslation } from 'react-i18next'
import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import classNames from 'classnames'
import { Grid01 } from '@/app/components/base/icons/src/vender/line/layout'
import { Grid01 as Grid01Solid } from '@/app/components/base/icons/src/vender/solid/layout'
type ExploreNavProps = {
className?: string
}
const ExploreNav = ({
className,
}: ExploreNavProps) => {
const { t } = useTranslation()
const selectedSegment = useSelectedLayoutSegment()
const actived = selectedSegment === 'explore'
return (
<Link href="/explore/apps" className={classNames(
className, 'group',
actived && 'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]',
actived ? 'text-primary-600' : 'text-gray-500 hover:bg-gray-200',
)}>
{
actived
? <Grid01Solid className='mr-2 w-4 h-4' />
: <Grid01 className='mr-2 w-4 h-4' />
}
{t('common.menus.explore')}
</Link>
)
}
export default ExploreNav

View File

@ -0,0 +1,40 @@
import { Github } from '@/app/components/base/icons/src/public/common'
import type { GithubRepo } from '@/models/common'
const getStar = async () => {
const res = await fetch('https://api.github.com/repos/langgenius/dify')
if (!res.ok)
throw new Error('Failed to fetch data')
return res.json()
}
const GithubStar = async () => {
let githubRepo: GithubRepo = { stargazers_count: 0 }
if (process.env.NODE_ENV === 'development')
return null
try {
githubRepo = await getStar()
}
catch (e) {
return null
}
return (
<a
href='https://github.com/langgenius/dify'
target='_blank'
className='flex items-center leading-[18px] border border-gray-200 rounded-md text-xs text-gray-700 font-semibold overflow-hidden'>
<div className='flex items-center px-2 py-1 bg-gray-100'>
<Github className='mr-1 w-[18px] h-[18px]' />
Star
</div>
<div className='px-2 py-1 bg-white border-l border-gray-200'>{`${githubRepo.stargazers_count}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
</a>
)
}
export default GithubStar

View File

@ -15,23 +15,8 @@
background-size: contain;
}
.github-icon {
width: 18px;
height: 18px;
background: url(./assets/github-icon.svg) center center no-repeat;
background-size: contain;
}
.alpha {
width: 12px;
height: 12px;
background: url(./assets/alpha.svg) center center no-repeat;
}
.beaker-icon {
width: 12px;
height: 12px;
margin-right: 4px;
background: url(./assets/beaker.svg) center center no-repeat;
background-size: contain;
}

View File

@ -1,138 +1,43 @@
'use client'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { usePathname, useSelectedLayoutSegment } from 'next/navigation'
import classNames from 'classnames'
import { CommandLineIcon } from '@heroicons/react/24/solid'
import Link from 'next/link'
import AccountDropdown from './account-dropdown'
import AppNav from './app-nav'
import DatasetNav from './dataset-nav'
import EnvNav from './env-nav'
import ExploreNav from './explore-nav'
import GithubStar from './github-star'
import PluginNav from './plugin-nav'
import s from './index.module.css'
import type { GithubRepo } from '@/models/common'
import { WorkspaceProvider } from '@/context/workspace-context'
import { useAppContext } from '@/context/app-context'
import { Grid01 } from '@/app/components/base/icons/src/vender/line/layout'
import { Grid01 as Grid01Solid } from '@/app/components/base/icons/src/vender/solid/layout'
import { PuzzlePiece01 } from '@/app/components/base/icons/src/vender/line/development'
import { PuzzlePiece01 as PuzzlePiece01Solid } from '@/app/components/base/icons/src/vender/solid/development'
const navClassName = `
flex items-center relative mr-3 px-3 h-8 rounded-xl
font-medium text-sm
cursor-pointer
`
const headerEnvClassName: { [k: string]: string } = {
DEVELOPMENT: 'bg-[#FEC84B] border-[#FDB022] text-[#93370D]',
TESTING: 'bg-[#A5F0FC] border-[#67E3F9] text-[#164C63]',
}
const Header = () => {
const { t } = useTranslation()
const pathname = usePathname()
const { userProfile, langeniusVersionInfo } = useAppContext()
const showEnvTag = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT'
const selectedSegment = useSelectedLayoutSegment()
const isPluginsComingSoon = selectedSegment === 'plugins-coming-soon'
const isExplore = selectedSegment === 'explore'
const [starCount, setStarCount] = useState(0)
const isBordered = ['/apps', '/datasets'].includes(pathname)
useEffect(() => {
globalThis.fetch('https://api.github.com/repos/langgenius/dify').then(res => res.json()).then((data: GithubRepo) => {
setStarCount(data.stargazers_count)
})
}, [])
return (
<div className={classNames(
'sticky top-0 left-0 right-0 z-20 flex bg-gray-100 grow-0 shrink-0 basis-auto h-14',
s.header,
isBordered ? 'border-b border-gray-200' : '',
)}
>
<div className={classNames(
s[`header-${langeniusVersionInfo.current_env}`],
'flex flex-1 items-center justify-between px-4',
)}>
<div className='flex items-center'>
<Link href="/apps" className='flex items-center mr-4'>
<div className={s.logo} />
</Link>
{
starCount > 0 && (
<Link
href='https://github.com/langgenius/dify'
target='_blank'
className='flex items-center leading-[18px] border border-gray-200 rounded-md text-xs text-gray-700 font-semibold overflow-hidden'>
<div className='flex items-center px-2 py-1 bg-gray-100'>
<div className={`${s['github-icon']} mr-1 rounded-full`} />
Star
</div>
<div className='px-2 py-1 bg-white border-l border-gray-200'>{`${starCount}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
</Link>
)
}
</div>
<div className='flex items-center'>
<Link href="/explore/apps" className={classNames(
navClassName, 'group',
isExplore && 'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]',
isExplore ? 'text-primary-600' : 'text-gray-500 hover:bg-gray-200',
)}>
{
isExplore
? <Grid01Solid className='mr-2 w-4 h-4' />
: <Grid01 className='mr-2 w-4 h-4' />
}
{t('common.menus.explore')}
</Link>
<AppNav />
<Link href="/plugins-coming-soon" className={classNames(
navClassName, 'group',
isPluginsComingSoon && 'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]',
isPluginsComingSoon ? 'text-primary-600' : 'text-gray-500 hover:bg-gray-200',
)}>
{
isPluginsComingSoon
? <PuzzlePiece01Solid className='mr-2 w-4 h-4' />
: <PuzzlePiece01 className='mr-2 w-4 h-4' />
}
{t('common.menus.plugins')}
</Link>
<DatasetNav />
</div>
<div className='flex items-center flex-shrink-0'>
{
showEnvTag && (
<div className={`
flex items-center h-[22px] mr-4 rounded-md px-2 text-xs font-medium border
${headerEnvClassName[langeniusVersionInfo.current_env]}
`}>
{
langeniusVersionInfo.current_env === 'TESTING' && (
<>
<div className={s['beaker-icon']} />
{t('common.environment.testing')}
</>
)
}
{
langeniusVersionInfo.current_env === 'DEVELOPMENT' && (
<>
<CommandLineIcon className='w-3 h-3 mr-1' />
{t('common.environment.development')}
</>
)
}
</div>
)
}
<WorkspaceProvider>
<AccountDropdown userProfile={userProfile} langeniusVersionInfo={langeniusVersionInfo} />
</WorkspaceProvider>
</div>
<>
<div className='flex items-center'>
<Link href="/apps" className='flex items-center mr-4'>
<div className={s.logo} />
</Link>
{/* @ts-expect-error Async Server Component */}
<GithubStar />
</div>
</div>
<div className='flex items-center'>
<ExploreNav className={navClassName} />
<AppNav />
<PluginNav className={navClassName} />
<DatasetNav />
</div>
<div className='flex items-center flex-shrink-0'>
<EnvNav />
<WorkspaceProvider>
<AccountDropdown />
</WorkspaceProvider>
</div>
</>
)
}
export default Header

View File

@ -0,0 +1,37 @@
'use client'
import { useTranslation } from 'react-i18next'
import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import classNames from 'classnames'
import { PuzzlePiece01 } from '@/app/components/base/icons/src/vender/line/development'
import { PuzzlePiece01 as PuzzlePiece01Solid } from '@/app/components/base/icons/src/vender/solid/development'
type PluginNavProps = {
className?: string
}
const PluginNav = ({
className,
}: PluginNavProps) => {
const { t } = useTranslation()
const selectedSegment = useSelectedLayoutSegment()
const isPluginsComingSoon = selectedSegment === 'plugins-coming-soon'
return (
<Link href="/plugins-coming-soon" className={classNames(
className, 'group',
isPluginsComingSoon && 'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]',
isPluginsComingSoon ? 'text-primary-600' : 'text-gray-500 hover:bg-gray-200',
)}>
{
isPluginsComingSoon
? <PuzzlePiece01Solid className='mr-2 w-4 h-4' />
: <PuzzlePiece01 className='mr-2 w-4 h-4' />
}
{t('common.menus.plugins')}
</Link>
)
}
export default PluginNav

View File

@ -67,7 +67,7 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
const result = await userProfileResponse.json()
setUserProfile(result)
const current_version = userProfileResponse.headers.get('x-version')
const current_env = userProfileResponse.headers.get('x-env')
const current_env = process.env.NODE_ENV === 'development' ? 'DEVELOPMENT' : userProfileResponse.headers.get('x-env')
const versionData = await fetchLanggeniusVersion({ url: '/version', params: { current_version } })
setLangeniusVersionInfo({ ...versionData, current_version, latest_version: versionData.version, current_env })
}