### What problem does this PR solve? Feat: Modify background color of Card #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.0
| @@ -0,0 +1,35 @@ | |||
| import * as AvatarPrimitive from '@radix-ui/react-avatar'; | |||
| import { random } from 'lodash'; | |||
| import { forwardRef } from 'react'; | |||
| import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; | |||
| const Colors = [ | |||
| { from: '#4F6DEE', to: '#67BDF9' }, | |||
| { from: '#38A04D', to: '#93DCA2' }, | |||
| { from: '#EDB395', to: '#C35F2B' }, | |||
| { from: '#633897', to: '#CBA1FF' }, | |||
| ]; | |||
| export const RAGFlowAvatar = forwardRef< | |||
| React.ElementRef<typeof AvatarPrimitive.Root>, | |||
| React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> & { | |||
| name?: string; | |||
| avatar?: string; | |||
| } | |||
| >(({ name, avatar, ...props }, ref) => { | |||
| const index = random(0, 3); | |||
| console.log('🚀 ~ index:', index); | |||
| const value = Colors[index]; | |||
| return ( | |||
| <Avatar ref={ref} {...props}> | |||
| <AvatarImage src={avatar} /> | |||
| <AvatarFallback | |||
| className={`bg-gradient-to-b from-[${value.from}] to-[${value.to}]`} | |||
| > | |||
| {name?.slice(0, 1)} | |||
| </AvatarFallback> | |||
| </Avatar> | |||
| ); | |||
| }); | |||
| RAGFlowAvatar.displayName = 'RAGFlowAvatar'; | |||
| @@ -9,7 +9,7 @@ const Card = React.forwardRef< | |||
| <div | |||
| ref={ref} | |||
| className={cn( | |||
| 'rounded-lg border bg-card text-card-foreground shadow-sm', | |||
| 'rounded-lg bg-background-card text-card-foreground shadow-sm', | |||
| className, | |||
| )} | |||
| {...props} | |||
| @@ -1,5 +1,5 @@ | |||
| import { RAGFlowAvatar } from '@/components/ragflow-avatar'; | |||
| import { useTheme } from '@/components/theme-provider'; | |||
| import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; | |||
| import { Badge } from '@/components/ui/badge'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { | |||
| @@ -48,7 +48,7 @@ export function Header() { | |||
| const { setTheme, theme } = useTheme(); | |||
| const { | |||
| data: { language = 'English' }, | |||
| data: { language = 'English', avatar, nickname }, | |||
| } = useFetchUserInfo(); | |||
| const handleItemClick = (key: string) => () => { | |||
| @@ -158,10 +158,12 @@ export function Header() { | |||
| {theme === 'light' ? <Sun /> : <Moon />} | |||
| </Button> | |||
| <div className="relative"> | |||
| <Avatar className="size-8 cursor-pointer" onClick={navigateToProfile}> | |||
| <AvatarImage src="https://github.com/shadcn.png" /> | |||
| <AvatarFallback>CN</AvatarFallback> | |||
| </Avatar> | |||
| <RAGFlowAvatar | |||
| name={nickname} | |||
| avatar={avatar} | |||
| className="size-8 cursor-pointer" | |||
| onClick={navigateToProfile} | |||
| ></RAGFlowAvatar> | |||
| <Badge className="h-5 w-8 absolute font-normal p-0 justify-center -right-8 -top-2 text-text-title-invert bg-gradient-to-l from-[#42D7E7] to-[#478AF5]"> | |||
| Pro | |||
| </Badge> | |||
| @@ -7,7 +7,7 @@ import { | |||
| import { useSetSelectedRecord } from '@/hooks/logic-hooks'; | |||
| import { useSelectParserList } from '@/hooks/user-setting-hooks'; | |||
| import { getExtension } from '@/utils/document-util'; | |||
| import { Divider, Flex, Switch, Table, Typography } from 'antd'; | |||
| import { Divider, Flex, Switch, Table, Tooltip, Typography } from 'antd'; | |||
| import type { ColumnsType } from 'antd/es/table'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import CreateFileModal from './create-file-modal'; | |||
| @@ -31,6 +31,7 @@ import FileUploadModal from '@/components/file-upload-modal'; | |||
| import { RunningStatus } from '@/constants/knowledge'; | |||
| import { IDocumentInfo } from '@/interfaces/database/document'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { CircleHelp } from 'lucide-react'; | |||
| import styles from './index.less'; | |||
| import { SetMetaModal } from './set-meta-modal'; | |||
| @@ -157,7 +158,14 @@ const KnowledgeFile = () => { | |||
| ), | |||
| }, | |||
| { | |||
| title: t('parsingStatus'), | |||
| title: ( | |||
| <span className="flex items-center gap-2"> | |||
| {t('parsingStatus')} | |||
| <Tooltip title={t('parsingStatusTip')}> | |||
| <CircleHelp className="size-3" /> | |||
| </Tooltip> | |||
| </span> | |||
| ), | |||
| dataIndex: 'run', | |||
| key: 'run', | |||
| filters: Object.entries(RunningStatus).map(([key, value]) => ({ | |||
| @@ -26,7 +26,7 @@ export function DatasetCard({ | |||
| return ( | |||
| <Card | |||
| key={dataset.id} | |||
| className="bg-colors-background-inverse-weak w-40" | |||
| className="w-40" | |||
| onClick={navigateToDataset(dataset.id)} | |||
| > | |||
| <CardContent className="p-2.5 pt-1 group"> | |||
| @@ -81,7 +81,7 @@ export function SeeAllCard() { | |||
| className="bg-colors-background-inverse-weak w-40" | |||
| onClick={navigateToDatasetList} | |||
| > | |||
| <CardContent className="p-2.5 pt-1 w-full h-full flex items-center justify-center gap-1.5"> | |||
| <CardContent className="p-2.5 pt-1 w-full h-full flex items-center justify-center gap-1.5 text-text-sub-title"> | |||
| See All <ChevronRight className="size-4" /> | |||
| </CardContent> | |||
| </Card> | |||
| @@ -1,6 +1,7 @@ | |||
| import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; | |||
| import { Card, CardContent } from '@/components/ui/card'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { ChevronRight } from 'lucide-react'; | |||
| type ApplicationCardProps = { | |||
| app: { | |||
| @@ -12,19 +13,33 @@ type ApplicationCardProps = { | |||
| export function ApplicationCard({ app }: ApplicationCardProps) { | |||
| return ( | |||
| <Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard w-64"> | |||
| <CardContent className="p-4 flex items-center gap-6"> | |||
| <Card className="w-[264px]"> | |||
| <CardContent className="p-2.5 flex items-center gap-2.5"> | |||
| <Avatar className="size-14 rounded-lg"> | |||
| <AvatarImage src={app.avatar === null ? '' : app.avatar} /> | |||
| <AvatarFallback className="rounded-lg">CN</AvatarFallback> | |||
| </Avatar> | |||
| <div className="flex-1"> | |||
| <h3 className="text-lg font-semibold line-clamp-1 mb-1"> | |||
| {app.title} | |||
| </h3> | |||
| <p className="text-sm opacity-80">{formatDate(app.update_time)}</p> | |||
| <h3 className="text-sm font-normal line-clamp-1 mb-1">{app.title}</h3> | |||
| <p className="text-xs font-normal text-text-sub-title"> | |||
| {formatDate(app.update_time)} | |||
| </p> | |||
| </div> | |||
| </CardContent> | |||
| </Card> | |||
| ); | |||
| } | |||
| export type SeeAllAppCardProps = { | |||
| click(): void; | |||
| }; | |||
| export function SeeAllAppCard({ click }: SeeAllAppCardProps) { | |||
| return ( | |||
| <Card className="w-64 min-h-[76px]" onClick={click}> | |||
| <CardContent className="p-2.5 pt-1 w-full h-full flex items-center justify-center gap-1.5 text-text-sub-title"> | |||
| See All <ChevronRight className="size-4" /> | |||
| </CardContent> | |||
| </Card> | |||
| ); | |||
| } | |||
| @@ -1,10 +1,11 @@ | |||
| import { Segmented, SegmentedValue } from '@/components/ui/segmented'; | |||
| import { Routes } from '@/routes'; | |||
| import { Cpu, MessageSquare, Search } from 'lucide-react'; | |||
| import { useMemo, useState } from 'react'; | |||
| import { useCallback, useMemo, useState } from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { useNavigate } from 'umi'; | |||
| import { Agents } from './agent-list'; | |||
| import { ApplicationCard } from './application-card'; | |||
| import { ApplicationCard, SeeAllAppCard } from './application-card'; | |||
| import { ChatList } from './chat-list'; | |||
| const applications = [ | |||
| @@ -38,15 +39,22 @@ const applications = [ | |||
| }, | |||
| ]; | |||
| const All = 'all'; | |||
| export function Applications() { | |||
| const [val, setVal] = useState('all'); | |||
| const { t } = useTranslation(); | |||
| const navigate = useNavigate(); | |||
| const handleNavigate = useCallback(() => { | |||
| navigate(val); | |||
| }, [navigate, val]); | |||
| const options = useMemo( | |||
| () => [ | |||
| { | |||
| label: 'All', | |||
| value: 'all', | |||
| value: All, | |||
| }, | |||
| { value: Routes.Chats, label: t('header.chat') }, | |||
| { value: Routes.Searches, label: t('header.search') }, | |||
| @@ -61,7 +69,7 @@ export function Applications() { | |||
| return ( | |||
| <section className="mt-12"> | |||
| <div className="flex justify-between items-center mb-6"> | |||
| <div className="flex justify-between items-center mb-5"> | |||
| <h2 className="text-2xl font-bold ">Applications</h2> | |||
| <Segmented | |||
| options={options} | |||
| @@ -71,13 +79,14 @@ export function Applications() { | |||
| ></Segmented> | |||
| </div> | |||
| <div className="flex flex-wrap gap-4"> | |||
| {(val === 'all' || val === Routes.Searches) && | |||
| {(val === All || val === Routes.Searches) && | |||
| [...Array(12)].map((_, i) => { | |||
| const app = applications[i % 4]; | |||
| return <ApplicationCard key={i} app={app}></ApplicationCard>; | |||
| })} | |||
| {val === Routes.Agents && <Agents></Agents>} | |||
| {val === Routes.Chats && <ChatList></ChatList>} | |||
| {val === All || <SeeAllAppCard click={handleNavigate}></SeeAllAppCard>} | |||
| </div> | |||
| </section> | |||
| ); | |||
| @@ -48,6 +48,7 @@ module.exports = { | |||
| 'text-sub-title': 'var(--text-sub-title)', | |||
| 'text-title-invert': 'var(--text-title-invert)', | |||
| 'background-header-bar': 'var(--background-header-bar)', | |||
| 'background-card': 'var(--background-card)', | |||
| primary: { | |||
| DEFAULT: 'hsl(var(--primary))', | |||
| @@ -82,6 +82,7 @@ | |||
| --background-header-bar: rgba(11, 11, 12, 1); | |||
| --text-title-invert: rgba(255, 255, 255, 1); | |||
| --background-card: rgba(22, 22, 24, 0.05); | |||
| } | |||
| .dark { | |||
| @@ -184,6 +185,8 @@ | |||
| --background-header-bar: rgba(11, 11, 12, 1); | |||
| --text-title-invert: rgba(22, 22, 24, 1); | |||
| --background-card: rgba(255, 255, 255, 0.05); | |||
| } | |||
| } | |||