From f5091297fe2975672846ac4b65f7cf8e020eea9c Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 11 Nov 2024 18:25:48 +0800 Subject: [PATCH] feat: Add custom background color #3221 --- web/package-lock.json | 56 ++++++++++++++ web/package.json | 2 + web/src/components/ui/avatar.tsx | 50 +++++++++++++ web/src/components/ui/container.tsx | 19 +++++ web/src/components/ui/segmented .tsx | 51 +++++++++++++ web/src/components/ui/tabs.tsx | 55 ++++++++++++++ web/src/pages/home/card.tsx | 39 ++++++++++ web/src/pages/home/header.tsx | 106 +++++++++++++++++++++++++++ web/src/pages/home/index.tsx | 15 ++++ web/src/routes.ts | 5 ++ web/tailwind.config.js | 6 +- web/tailwind.css | 6 ++ 12 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 web/src/components/ui/avatar.tsx create mode 100644 web/src/components/ui/container.tsx create mode 100644 web/src/components/ui/segmented .tsx create mode 100644 web/src/components/ui/tabs.tsx create mode 100644 web/src/pages/home/card.tsx create mode 100644 web/src/pages/home/header.tsx create mode 100644 web/src/pages/home/index.tsx diff --git a/web/package-lock.json b/web/package-lock.json index 48ef9a83bb..0960f763b2 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -13,6 +13,7 @@ "@hookform/resolvers": "^3.9.1", "@js-preview/excel": "^1.7.8", "@monaco-editor/react": "^4.6.0", + "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.1", @@ -22,6 +23,7 @@ "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-toast": "^1.2.2", "@tanstack/react-query": "^5.40.0", "@tanstack/react-query-devtools": "^5.51.5", @@ -4083,6 +4085,31 @@ } } }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-avatar/-/react-avatar-1.1.1.tgz", + "integrity": "sha512-eoOtThOmxeoizxpX6RiEsQZ2wj5r4+zoeqAwO0cBaFQGjJwIH3dIX0OCxNrCyrrdxG+vBweMETh3VziQG7c1kw==", + "dependencies": { + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-checkbox": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/@radix-ui/react-checkbox/-/react-checkbox-1.1.2.tgz", @@ -4702,6 +4729,35 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-tabs/-/react-tabs-1.1.1.tgz", + "integrity": "sha512-3GBUDmP2DvzmtYLMsHmpA1GtR46ZDZ+OreXM/N+kkQJOPIgytFWWTfDQmBQKBvaFS0Vno0FktdbVzN28KGrMdw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-toast": { "version": "1.2.2", "resolved": "https://registry.npmmirror.com/@radix-ui/react-toast/-/react-toast-1.2.2.tgz", diff --git a/web/package.json b/web/package.json index 515d7aa78f..d6d1cdc6f6 100644 --- a/web/package.json +++ b/web/package.json @@ -24,6 +24,7 @@ "@hookform/resolvers": "^3.9.1", "@js-preview/excel": "^1.7.8", "@monaco-editor/react": "^4.6.0", + "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.1", @@ -33,6 +34,7 @@ "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-toast": "^1.2.2", "@tanstack/react-query": "^5.40.0", "@tanstack/react-query-devtools": "^5.51.5", diff --git a/web/src/components/ui/avatar.tsx b/web/src/components/ui/avatar.tsx new file mode 100644 index 0000000000..e30079b5e2 --- /dev/null +++ b/web/src/components/ui/avatar.tsx @@ -0,0 +1,50 @@ +'use client'; + +import * as AvatarPrimitive from '@radix-ui/react-avatar'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarFallback, AvatarImage }; diff --git a/web/src/components/ui/container.tsx b/web/src/components/ui/container.tsx new file mode 100644 index 0000000000..7c69e97f27 --- /dev/null +++ b/web/src/components/ui/container.tsx @@ -0,0 +1,19 @@ +import { cn } from '@/lib/utils'; + +export function Container({ + children, + className, + ...props +}: React.PropsWithChildren>) { + return ( +
+ {children} +
+ ); +} diff --git a/web/src/components/ui/segmented .tsx b/web/src/components/ui/segmented .tsx new file mode 100644 index 0000000000..bab1427024 --- /dev/null +++ b/web/src/components/ui/segmented .tsx @@ -0,0 +1,51 @@ +import { cn } from '@/lib/utils'; +import * as React from 'react'; +export declare type SegmentedValue = string | number; +export declare type SegmentedRawOption = SegmentedValue; +export interface SegmentedLabeledOption { + className?: string; + disabled?: boolean; + label: React.ReactNode; + value: SegmentedRawOption; + /** + * html `title` property for label + */ + title?: string; +} +declare type SegmentedOptions = (SegmentedRawOption | SegmentedLabeledOption)[]; +export interface SegmentedProps + extends Omit, 'onChange'> { + options: SegmentedOptions; + defaultValue?: SegmentedValue; + value?: SegmentedValue; + onChange?: (value: SegmentedValue) => void; + disabled?: boolean; + prefixCls?: string; + direction?: 'ltr' | 'rtl'; + motionName?: string; +} + +export function Segmented({ options, value, onChange }: SegmentedProps) { + return ( +
+ {options.map((option) => { + const isObject = typeof option === 'object'; + const actualValue = isObject ? option.value : option; + + return ( +
onChange?.(actualValue)} + > + {isObject ? option.label : option} +
+ ); + })} +
+ ); +} diff --git a/web/src/components/ui/tabs.tsx b/web/src/components/ui/tabs.tsx new file mode 100644 index 0000000000..299dcaed14 --- /dev/null +++ b/web/src/components/ui/tabs.tsx @@ -0,0 +1,55 @@ +'use client'; + +import * as TabsPrimitive from '@radix-ui/react-tabs'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Tabs = TabsPrimitive.Root; + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsList.displayName = TabsPrimitive.List.displayName; + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsContent.displayName = TabsPrimitive.Content.displayName; + +export { Tabs, TabsContent, TabsList, TabsTrigger }; diff --git a/web/src/pages/home/card.tsx b/web/src/pages/home/card.tsx new file mode 100644 index 0000000000..881b44a0bf --- /dev/null +++ b/web/src/pages/home/card.tsx @@ -0,0 +1,39 @@ +import { Button } from '@/components/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; + +export function CardWithForm() { + return ( + + + Create project + Deploy your new project in one-click. + + +
+
+
+ + +
+
+ +
+
+
+
+ + + + +
+ ); +} diff --git a/web/src/pages/home/header.tsx b/web/src/pages/home/header.tsx new file mode 100644 index 0000000000..80a687de32 --- /dev/null +++ b/web/src/pages/home/header.tsx @@ -0,0 +1,106 @@ +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { Button } from '@/components/ui/button'; +import { Container } from '@/components/ui/container'; +import { Segmented, SegmentedValue } from '@/components/ui/segmented '; +import { useTranslate } from '@/hooks/common-hooks'; +import { useNavigateWithFromState } from '@/hooks/route-hook'; +import { + Cpu, + Github, + Library, + MessageSquareText, + Search, + Star, + Zap, +} from 'lucide-react'; +import { useCallback, useMemo, useState } from 'react'; +import { useLocation } from 'umi'; + +export function HomeHeader() { + const { t } = useTranslate('header'); + const { pathname } = useLocation(); + const navigate = useNavigateWithFromState(); + const [currentPath, setCurrentPath] = useState('/home'); + + const tagsData = useMemo( + () => [ + { path: '/home', name: t('knowledgeBase'), icon: Library }, + { path: '/chat', name: t('chat'), icon: MessageSquareText }, + { path: '/search', name: t('search'), icon: Search }, + { path: '/flow', name: t('flow'), icon: Cpu }, + // { path: '/file', name: t('fileManager'), icon: FileIcon }, + ], + [t], + ); + + const options = useMemo(() => { + return tagsData.map((tag) => { + const HeaderIcon = tag.icon; + + return { + label: ( +
+ + {tag.name} +
+ ), + value: tag.path, + }; + }); + }, [tagsData]); + + // const currentPath = useMemo(() => { + // return tagsData.find((x) => pathname.startsWith(x.path))?.name || 'home'; + // }, [pathname, tagsData]); + + const handleChange = (path: SegmentedValue) => { + // navigate(path as string); + setCurrentPath(path as string); + }; + + const handleLogoClick = useCallback(() => { + navigate('/'); + }, [navigate]); + + return ( +
+
+ logo + +
+
+ +
+
+ + + + + CN + + yifanwu92@gmail.com + + +
+
+ ); +} diff --git a/web/src/pages/home/index.tsx b/web/src/pages/home/index.tsx new file mode 100644 index 0000000000..e9aa7cef45 --- /dev/null +++ b/web/src/pages/home/index.tsx @@ -0,0 +1,15 @@ +import { CardWithForm } from './card'; +import { HomeHeader } from './header'; + +const Home = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default Home; diff --git a/web/src/routes.ts b/web/src/routes.ts index d72e52b4e5..7300a2a343 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -126,6 +126,11 @@ const routes = [ component: '@/pages/demo', layout: false, }, + { + path: '/home', + layout: false, + component: '@/pages/home', + }, ]; export default routes; diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 8bf18331c0..861040035a 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -3,7 +3,7 @@ const { fontFamily } = require('tailwindcss/defaultTheme'); /** @type {import('tailwindcss').Config} */ module.exports = { - darkMode: ['class'], + darkMode: ['selector'], content: [ './src/pages/**/*.tsx', './src/components/**/*.tsx', @@ -52,6 +52,10 @@ module.exports = { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))', }, + backgroundInverseStandard: { + DEFAULT: 'var(--background-inverse-standard)', + foreground: 'var(--background-inverse-standard-foreground)', + }, }, borderRadius: { lg: `var(--radius)`, diff --git a/web/tailwind.css b/web/tailwind.css index 3cff4e2148..be048d8f46 100644 --- a/web/tailwind.css +++ b/web/tailwind.css @@ -34,6 +34,9 @@ --ring: 215 20.2% 65.1%; --radius: 0.5rem; + + --background-inverse-standard: rgba(58, 56, 65, 0.15); + --background-inverse-standard-foreground: rgb(92, 81, 81); } .dark { @@ -67,6 +70,9 @@ --ring: 216 34% 17%; --radius: 0.5rem; + + --background-inverse-standard: rgba(230, 227, 246, 0.15); + --background-inverse-standard-foreground: rgba(255, 255, 255, 1); } }