From f5c13bc7b1dabed1a28247183a2eb5373c7ccb06 Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 25 Nov 2024 16:07:49 +0800 Subject: [PATCH] Feat: Add PricingCard component #3221 --- web/src/components/ui/badge.tsx | 2 + web/src/components/ui/button.tsx | 4 +- web/src/pages/home/datasets.tsx | 2 +- web/src/pages/profile-setting/plan/index.tsx | 120 +++++++++++++++++- .../profile-setting/plan/pricing-card.tsx | 90 +++++++++++++ web/tailwind.config.js | 3 + web/tailwind.css | 6 + 7 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 web/src/pages/profile-setting/plan/pricing-card.tsx diff --git a/web/src/components/ui/badge.tsx b/web/src/components/ui/badge.tsx index d7e8ee842a5..2ccf66c25d3 100644 --- a/web/src/components/ui/badge.tsx +++ b/web/src/components/ui/badge.tsx @@ -15,6 +15,8 @@ const badgeVariants = cva( destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', outline: 'text-foreground', + tertiary: + 'border-transparent bg-colors-text-core-standard text-foreground hover:bg-colors-text-core-standard/80', }, }, defaultVariants: { diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx index bd2c5eb8854..10c902afda0 100644 --- a/web/src/components/ui/button.tsx +++ b/web/src/components/ui/button.tsx @@ -13,11 +13,13 @@ const buttonVariants = cva( destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', outline: - 'border border-colors-outline-sentiment-primary bg-background hover:bg-accent hover:text-accent-foreground', + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', ghost: 'hover:bg-accent hover:text-accent-foreground', link: 'text-primary underline-offset-4 hover:underline', + tertiary: + 'bg-colors-text-core-standard text-foreground hover:bg-colors-text-core-standard/80', }, size: { default: 'h-10 px-4 py-2', diff --git a/web/src/pages/home/datasets.tsx b/web/src/pages/home/datasets.tsx index 1f694052afb..4fd0bf20d96 100644 --- a/web/src/pages/home/datasets.tsx +++ b/web/src/pages/home/datasets.tsx @@ -76,7 +76,7 @@ export function Datasets() { ))} - diff --git a/web/src/pages/profile-setting/plan/index.tsx b/web/src/pages/profile-setting/plan/index.tsx index d6cd5869ae7..897d45e4a0d 100644 --- a/web/src/pages/profile-setting/plan/index.tsx +++ b/web/src/pages/profile-setting/plan/index.tsx @@ -1,3 +1,121 @@ +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { Segmented, SegmentedValue } from '@/components/ui/segmented '; +import { CircleCheckBig, LogOut } from 'lucide-react'; +import { useMemo, useState } from 'react'; +import { PricingCard } from './pricing-card'; + +const pricingData = [ + { + title: 'Free', + price: '$0', + description: 'Meh, just looking', + features: [ + { name: 'Project', value: '1 project' }, + { name: 'Storage', value: '1 Gb' }, + { name: 'Team', value: '2 members' }, + { name: 'Features', value: 'Basic features' }, + ], + buttonText: 'Current plan', + buttonVariant: 'outline' as const, + }, + { + title: 'Pro', + price: '$16.00', + description: 'For professional use.', + features: [ + { name: 'Project', value: 'Unlimited projects' }, + { name: 'Storage', value: '100 Gb' }, + { name: 'Team', value: 'Unlimited members' }, + { name: 'Features', value: 'Basic features All advanced features' }, + ], + buttonText: 'Upgrade', + buttonVariant: 'default' as const, + isPro: true, + }, + { + title: 'Enterprise', + price: 'Customed', + description: + 'Get full capabilities and support for large-scale mission-critical systems.', + features: [ + { name: 'Project', value: 'Unlimited projects' }, + { name: 'Storage', value: '100 Gb' }, + { name: 'Team', value: 'Unlimited members' }, + { name: 'Features', value: 'Basic features All advanced features' }, + ], + buttonText: 'Contact us', + buttonVariant: 'secondary' as const, + isEnterprise: true, + }, +]; + export default function Plan() { - return
plan
; + const [val, setVal] = useState('monthly'); + const options = useMemo(() => { + return [ + { + label: 'Monthly', + value: 'monthly', + }, + { + label: 'Yearly', + value: 'yearly', + }, + ]; + }, []); + + const handleChange = (path: SegmentedValue) => { + setVal(path as string); + }; + + const list = [ + 'Full access to pro features', + 'Exclusive analyze models', + 'Create more teams', + 'Invite more collaborators', + ]; + + return ( +
+

Plan & balance

+ +
+ Balance + $ 100.00 +
+
+ The value equals to 1,000 tokens or 10.00 GBs of storage + +
+
+ + +
Upgrade to access
+
+ {list.map((x, idx) => ( +
+ + {x} +
+ ))} +
+ +
+ {pricingData.map((plan, index) => ( + + ))} +
+
+
+
+ ); } diff --git a/web/src/pages/profile-setting/plan/pricing-card.tsx b/web/src/pages/profile-setting/plan/pricing-card.tsx new file mode 100644 index 00000000000..13354f631bb --- /dev/null +++ b/web/src/pages/profile-setting/plan/pricing-card.tsx @@ -0,0 +1,90 @@ +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader } from '@/components/ui/card'; +import { cn } from '@/lib/utils'; +import { Mail, Zap } from 'lucide-react'; + +interface PricingFeature { + name: string; + value: string; + tooltip?: string; +} + +interface PricingCardProps { + title: string; + price: string; + description: string; + features: PricingFeature[]; + buttonText: string; + buttonVariant?: 'default' | 'outline' | 'secondary'; + badge?: string; + isPro?: boolean; + isEnterprise?: boolean; +} + +export function PricingCard({ + title, + price, + description, + features, + buttonText, + isPro, + isEnterprise, +}: PricingCardProps) { + const isFree = title === 'Free'; + + return ( + + +
+
+ + {isPro && } + {isEnterprise && } + {title} + +
+

+ {description} +

+
+
+
+ {price} + {price !== 'Customed' && ( + /mo + )} +
+ +
+
+ +
    + {features.map((feature, index) => ( +
  • +
    + {feature.name} +
    + + {feature.value} + +
  • + ))} +
+
+
+ ); +} diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 36c48d139a2..c558d594b1e 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -28,8 +28,11 @@ module.exports = { 'colors-outline-sentiment-primary': 'var(--colors-outline-sentiment-primary)', + 'colors-outline-neutral-strong': 'var(--colors-outline-neutral-strong)', 'colors-text-core-standard': 'var(--colors-text-core-standard)', + 'colors-text-neutral-strong': 'var(--colors-text-neutral-strong)', + 'colors-text-neutral-standard': 'var(--colors-text-neutral-standard)', primary: { DEFAULT: 'hsl(var(--primary))', diff --git a/web/tailwind.css b/web/tailwind.css index 4e43b89e238..a8dd5a7c299 100644 --- a/web/tailwind.css +++ b/web/tailwind.css @@ -41,8 +41,11 @@ --button-blue-text: rgb(22, 119, 255); --colors-outline-sentiment-primary: rgba(127, 105, 255, 1); + --colors-outline-neutral-strong: rgba(112, 107, 107, 0.15); --colors-text-core-standard: rgba(127, 105, 255, 1); + --colors-text-neutral-strong: rgb(130, 121, 121); + --colors-text-neutral-standard: rgba(230, 227, 246, 1); } .dark { @@ -114,8 +117,11 @@ --colors-background-neutral-weak: rgba(17, 16, 23, 1); --colors-outline-sentiment-primary: rgba(146, 118, 255, 1); + --colors-outline-neutral-strong: rgba(255, 255, 255, 0.15); --colors-text-core-standard: rgba(137, 126, 255, 1); + --colors-text-neutral-strong: rgba(255, 255, 255, 1); + --colors-text-neutral-standard: rgba(230, 227, 246, 1); } }