dify
This commit is contained in:
44
dify/web/app/components/base/logo/dify-logo.tsx
Normal file
44
dify/web/app/components/base/logo/dify-logo.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import classNames from '@/utils/classnames'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import { basePath } from '@/utils/var'
|
||||
export type LogoStyle = 'default' | 'monochromeWhite'
|
||||
|
||||
export const logoPathMap: Record<LogoStyle, string> = {
|
||||
default: '/logo/logo.svg',
|
||||
monochromeWhite: '/logo/logo-monochrome-white.svg',
|
||||
}
|
||||
|
||||
export type LogoSize = 'large' | 'medium' | 'small'
|
||||
|
||||
export const logoSizeMap: Record<LogoSize, string> = {
|
||||
large: 'w-16 h-7',
|
||||
medium: 'w-12 h-[22px]',
|
||||
small: 'w-9 h-4',
|
||||
}
|
||||
|
||||
type DifyLogoProps = {
|
||||
style?: LogoStyle
|
||||
size?: LogoSize
|
||||
className?: string
|
||||
}
|
||||
|
||||
const DifyLogo: FC<DifyLogoProps> = ({
|
||||
style = 'default',
|
||||
size = 'medium',
|
||||
className,
|
||||
}) => {
|
||||
const { theme } = useTheme()
|
||||
const themedStyle = (theme === 'dark' && style === 'default') ? 'monochromeWhite' : style
|
||||
|
||||
return (
|
||||
<img
|
||||
src={`${basePath}${logoPathMap[themedStyle]}`}
|
||||
className={classNames('block object-contain', logoSizeMap[size], className)}
|
||||
alt='Dify logo'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default DifyLogo
|
||||
82
dify/web/app/components/base/logo/index.stories.tsx
Normal file
82
dify/web/app/components/base/logo/index.stories.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { Meta, StoryObj } from '@storybook/nextjs'
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
import type { ReactNode } from 'react'
|
||||
import DifyLogo from './dify-logo'
|
||||
import LogoSite from './logo-site'
|
||||
import LogoEmbeddedChatHeader from './logo-embedded-chat-header'
|
||||
import LogoEmbeddedChatAvatar from './logo-embedded-chat-avatar'
|
||||
|
||||
const meta = {
|
||||
title: 'Base/General/Logo',
|
||||
component: DifyLogo,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
docs: {
|
||||
description: {
|
||||
component: 'Brand assets rendered in different contexts. DifyLogo adapts to the active theme while other variants target specific surfaces.',
|
||||
},
|
||||
},
|
||||
},
|
||||
args: {
|
||||
size: 'medium',
|
||||
style: 'default',
|
||||
},
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'radio',
|
||||
options: ['large', 'medium', 'small'],
|
||||
},
|
||||
style: {
|
||||
control: 'radio',
|
||||
options: ['default', 'monochromeWhite'],
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof DifyLogo>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
const ThemePreview = ({ theme, children }: { theme: 'light' | 'dark'; children: ReactNode }) => {
|
||||
return (
|
||||
<ThemeProvider attribute="data-theme" forcedTheme={theme} enableSystem={false}>
|
||||
<div
|
||||
className={'min-w-[320px] rounded-2xl border border-divider-subtle bg-background-default-subtle p-6 shadow-sm'}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const Playground: Story = {
|
||||
render: ({ size, style }) => {
|
||||
return (
|
||||
<ThemePreview theme="dark">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-xs uppercase tracking-[0.18em] text-text-tertiary">Primary logo</span>
|
||||
<div className="flex items-center justify-between rounded-xl border border-divider-subtle bg-background-default p-4">
|
||||
<DifyLogo size={size} style={style} />
|
||||
<code className="text-[11px] text-text-tertiary">{`size="${size}" | style="${style}"`}</code>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<div className="flex flex-col gap-2 rounded-xl border border-divider-subtle bg-background-default p-4">
|
||||
<span className="text-[11px] font-medium uppercase tracking-[0.1em] text-text-tertiary">Site favicon</span>
|
||||
<LogoSite />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 rounded-xl border border-divider-subtle bg-background-default p-4">
|
||||
<span className="text-[11px] font-medium uppercase tracking-[0.1em] text-text-tertiary">Embedded header</span>
|
||||
<LogoEmbeddedChatHeader />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 rounded-xl border border-divider-subtle bg-background-default p-4 sm:col-span-2">
|
||||
<span className="text-[11px] font-medium uppercase tracking-[0.1em] text-text-tertiary">Embedded avatar</span>
|
||||
<LogoEmbeddedChatAvatar className="border-divider-strong rounded-2xl border" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ThemePreview>
|
||||
)
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { FC } from 'react'
|
||||
import { basePath } from '@/utils/var'
|
||||
|
||||
type LogoEmbeddedChatAvatarProps = {
|
||||
className?: string
|
||||
}
|
||||
const LogoEmbeddedChatAvatar: FC<LogoEmbeddedChatAvatarProps> = ({
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<img
|
||||
src={`${basePath}/logo/logo-embedded-chat-avatar.png`}
|
||||
className={`block h-10 w-10 ${className}`}
|
||||
alt='logo'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default LogoEmbeddedChatAvatar
|
||||
@@ -0,0 +1,24 @@
|
||||
import classNames from '@/utils/classnames'
|
||||
import type { FC } from 'react'
|
||||
import { basePath } from '@/utils/var'
|
||||
|
||||
type LogoEmbeddedChatHeaderProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const LogoEmbeddedChatHeader: FC<LogoEmbeddedChatHeaderProps> = ({
|
||||
className,
|
||||
}) => {
|
||||
return <picture>
|
||||
<source media="(resolution: 1x)" srcSet='/logo/logo-embedded-chat-header.png' />
|
||||
<source media="(resolution: 2x)" srcSet='/logo/logo-embedded-chat-header@2x.png' />
|
||||
<source media="(resolution: 3x)" srcSet='/logo/logo-embedded-chat-header@3x.png' />
|
||||
<img
|
||||
src={`${basePath}/logo/logo-embedded-chat-header.png`}
|
||||
alt='logo'
|
||||
className={classNames('block h-6 w-auto', className)}
|
||||
/>
|
||||
</picture>
|
||||
}
|
||||
|
||||
export default LogoEmbeddedChatHeader
|
||||
22
dify/web/app/components/base/logo/logo-site.tsx
Normal file
22
dify/web/app/components/base/logo/logo-site.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { basePath } from '@/utils/var'
|
||||
import classNames from '@/utils/classnames'
|
||||
|
||||
type LogoSiteProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const LogoSite: FC<LogoSiteProps> = ({
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<img
|
||||
src={`${basePath}/logo/logo.png`}
|
||||
className={classNames('block h-[24.5px] w-[22.651px]', className)}
|
||||
alt='logo'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default LogoSite
|
||||
Reference in New Issue
Block a user