|
1 | 1 | import React from 'react'; |
2 | | -import { Button, Card, Flex, Grid, Heading, Paragraph, Progress, Segmented, Tag, Text } from '@tiny-design/react'; |
| 2 | +import { IconArrowRight, IconCheckCircle } from '@tiny-design/icons'; |
| 3 | +import { Button, Card, Flex, Switch, Text } from '@tiny-design/react'; |
| 4 | + |
| 5 | +type BillingCycle = 'monthly' | 'yearly'; |
| 6 | + |
| 7 | +type Plan = { |
| 8 | + name: string; |
| 9 | + caption: string; |
| 10 | + monthlyPrice: string; |
| 11 | + yearlyPrice: string; |
| 12 | + monthlyNote: string; |
| 13 | + yearlyNote: string; |
| 14 | + features: string[]; |
| 15 | +}; |
| 16 | + |
| 17 | +const plans: Plan[] = [ |
| 18 | + { |
| 19 | + name: 'Plus', |
| 20 | + caption: 'For personal use', |
| 21 | + monthlyPrice: '$24', |
| 22 | + yearlyPrice: '$19', |
| 23 | + monthlyNote: 'Billed monthly', |
| 24 | + yearlyNote: 'Billed $228 annually', |
| 25 | + features: [ |
| 26 | + 'Up to 5 team members', |
| 27 | + 'Basic components library', |
| 28 | + 'Community support', |
| 29 | + '1GB storage space', |
| 30 | + ], |
| 31 | + }, |
| 32 | + { |
| 33 | + name: 'Pro', |
| 34 | + caption: 'For professionals', |
| 35 | + monthlyPrice: '$59', |
| 36 | + yearlyPrice: '$49', |
| 37 | + monthlyNote: 'Billed monthly', |
| 38 | + yearlyNote: 'Billed $588 annually', |
| 39 | + features: [ |
| 40 | + 'Everything in Plus, and:', |
| 41 | + 'Unlimited team members', |
| 42 | + 'Advanced components', |
| 43 | + 'Priority support', |
| 44 | + 'Unlimited storage', |
| 45 | + ], |
| 46 | + }, |
| 47 | +]; |
3 | 48 |
|
4 | 49 | export function PricingPreview(): React.ReactElement { |
| 50 | + const [billing, setBilling] = React.useState<BillingCycle>('yearly'); |
| 51 | + |
5 | 52 | return ( |
6 | | - <Flex vertical className="theme-studio__preview-stack"> |
7 | | - <Flex justify="space-between" align="flex-start" className="theme-studio__pricing-hero"> |
8 | | - <Flex vertical> |
9 | | - <Text className="theme-studio__eyebrow">Pricing</Text> |
10 | | - <Heading level={2}>Simple pricing for modern teams</Heading> |
11 | | - <Paragraph> |
12 | | - Choose a plan that scales from solo work to multi-product organizations. |
13 | | - </Paragraph> |
14 | | - <Flex className="theme-studio__pill-row"> |
15 | | - <Tag color="success">No setup fee</Tag> |
16 | | - <Tag>Cancel anytime</Tag> |
| 53 | + <div className="theme-studio__pricing-shell"> |
| 54 | + <Flex vertical className="theme-studio__pricing-stage"> |
| 55 | + <Flex vertical align="center" className="theme-studio__pricing-intro"> |
| 56 | + <h2 className="theme-studio__pricing-title">Pricing</h2> |
| 57 | + <Text className="theme-studio__pricing-subtitle">Check out our affordable pricing plans</Text> |
| 58 | + <Flex gap="sm" align='center'> |
| 59 | + <span className={billing === 'monthly' ? 'theme-studio__pricing-switch-label theme-studio__pricing-switch-label_active' : 'theme-studio__pricing-switch-label'}> |
| 60 | + Monthly |
| 61 | + </span> |
| 62 | + <Switch |
| 63 | + checked={billing === 'yearly'} |
| 64 | + onChange={(checked) => setBilling(checked ? 'yearly' : 'monthly')} |
| 65 | + /> |
| 66 | + <span className={billing === 'yearly' ? 'theme-studio__pricing-switch-label theme-studio__pricing-switch-label_active' : 'theme-studio__pricing-switch-label'}> |
| 67 | + Yearly |
| 68 | + </span> |
17 | 69 | </Flex> |
18 | 70 | </Flex> |
19 | | - <Segmented |
20 | | - options={[ |
21 | | - { label: 'Monthly', value: 'monthly' }, |
22 | | - { label: 'Yearly', value: 'yearly' }, |
23 | | - ]} |
24 | | - value="monthly" |
25 | | - /> |
26 | | - </Flex> |
27 | 71 |
|
28 | | - <Grid className="theme-studio__pricing-grid" minColumnWidth={240} gap="sm"> |
29 | | - {[ |
30 | | - { |
31 | | - name: 'Starter', |
32 | | - price: '$29', |
33 | | - description: 'Perfect for small businesses.', |
34 | | - features: ['1 workspace', 'Basic analytics', 'Community support'], |
35 | | - }, |
36 | | - { |
37 | | - name: 'Pro', |
38 | | - price: '$89', |
39 | | - description: 'More features and storage.', |
40 | | - featured: true, |
41 | | - features: ['5 workspaces', 'Advanced analytics', 'Priority support'], |
42 | | - }, |
43 | | - { |
44 | | - name: 'Scale', |
45 | | - price: '$199', |
46 | | - description: 'For larger teams and advanced reporting.', |
47 | | - features: ['Unlimited workspaces', 'SSO + audit log', 'Dedicated onboarding'], |
48 | | - }, |
49 | | - ].map((plan) => ( |
50 | | - <Card |
51 | | - key={plan.name} |
52 | | - className={`theme-studio__pricing-card${plan.featured ? ' theme-studio__pricing-card_featured' : ''}`}> |
53 | | - <Card.Content> |
54 | | - <Flex align="center" className="theme-studio__pricing-card-head"> |
55 | | - {plan.featured ? <Tag color="success">Popular</Tag> : null} |
56 | | - <Text strong>{plan.name}</Text> |
57 | | - </Flex> |
58 | | - <Flex vertical className="theme-studio__pricing-price"> |
59 | | - <Heading level={2}>{plan.price}</Heading> |
60 | | - <Text type="secondary">Per workspace / month</Text> |
61 | | - </Flex> |
62 | | - <Paragraph>{plan.description}</Paragraph> |
63 | | - <Flex vertical className="theme-studio__pricing-feature-list"> |
64 | | - {plan.features.map((feature) => ( |
65 | | - <Text key={feature}>{feature}</Text> |
66 | | - ))} |
67 | | - </Flex> |
68 | | - <Flex className="theme-studio__pricing-card-footer"> |
69 | | - <Button variant="solid" color={plan.featured ? 'primary' : 'default'}> |
70 | | - {plan.featured ? 'Upgrade plan' : 'Choose plan'} |
71 | | - </Button> |
72 | | - </Flex> |
73 | | - </Card.Content> |
74 | | - </Card> |
75 | | - ))} |
76 | | - </Grid> |
| 72 | + <div className="theme-studio__pricing-grid"> |
| 73 | + {plans.map((plan) => { |
| 74 | + const price = billing === 'yearly' ? plan.yearlyPrice : plan.monthlyPrice; |
| 75 | + const note = billing === 'yearly' ? plan.yearlyNote : plan.monthlyNote; |
77 | 76 |
|
78 | | - <Grid className="theme-studio__preview-grid" minColumnWidth={280} gap="sm"> |
79 | | - <Card title="Frequently Asked Questions" className="theme-studio__preview-card"> |
80 | | - <Card.Content> |
81 | | - <Flex vertical className="theme-studio__faq-list"> |
82 | | - <Flex vertical className="theme-studio__faq-item"> |
83 | | - <Text strong>Can I cancel anytime?</Text> |
84 | | - <Text type="secondary">Yes. Plans can be changed or canceled without lock-in.</Text> |
85 | | - </Flex> |
86 | | - <Flex vertical className="theme-studio__faq-item"> |
87 | | - <Text strong>Do you offer team migration?</Text> |
88 | | - <Text type="secondary">Pro and Scale include assisted import and onboarding.</Text> |
89 | | - </Flex> |
90 | | - </Flex> |
91 | | - </Card.Content> |
92 | | - </Card> |
93 | | - <Card title="Usage Snapshot" className="theme-studio__preview-card"> |
94 | | - <Card.Content> |
95 | | - <Flex vertical className="theme-studio__settings-list"> |
96 | | - <Flex vertical> |
97 | | - <Text strong>Seats</Text> |
98 | | - <Progress.Bar percent={68} /> |
99 | | - </Flex> |
100 | | - <Flex vertical> |
101 | | - <Text strong>Storage</Text> |
102 | | - <Progress.Bar percent={42} /> |
103 | | - </Flex> |
104 | | - </Flex> |
105 | | - </Card.Content> |
106 | | - </Card> |
107 | | - </Grid> |
108 | | - </Flex> |
| 77 | + return ( |
| 78 | + <Card key={plan.name} className="theme-studio__pricing-card"> |
| 79 | + <Card.Content> |
| 80 | + <Flex vertical className="theme-studio__pricing-card-content"> |
| 81 | + <div> |
| 82 | + <h3 className="theme-studio__pricing-plan">{plan.name}</h3> |
| 83 | + <Text className="theme-studio__pricing-caption">{plan.caption}</Text> |
| 84 | + </div> |
| 85 | + |
| 86 | + <div className="theme-studio__pricing-price-block"> |
| 87 | + <div className="theme-studio__pricing-price">{price}</div> |
| 88 | + <Text className="theme-studio__pricing-note">{note}</Text> |
| 89 | + </div> |
| 90 | + |
| 91 | + <div className="theme-studio__pricing-divider" /> |
| 92 | + |
| 93 | + <ul className="theme-studio__pricing-features"> |
| 94 | + {plan.features.map((feature) => ( |
| 95 | + <li key={feature} className="theme-studio__pricing-feature"> |
| 96 | + <IconCheckCircle size={16} className="theme-studio__pricing-feature-icon" /> |
| 97 | + <Text className={feature === 'Everything in Plus, and:' ? 'theme-studio__pricing-feature-text theme-studio__pricing-feature-text_strong' : 'theme-studio__pricing-feature-text'}> |
| 98 | + {feature} |
| 99 | + </Text> |
| 100 | + </li> |
| 101 | + ))} |
| 102 | + </ul> |
| 103 | + |
| 104 | + <Button variant="solid" color="primary" size="lg" className="theme-studio__pricing-action"> |
| 105 | + Purchase |
| 106 | + <IconArrowRight size={16} /> |
| 107 | + </Button> |
| 108 | + </Flex> |
| 109 | + </Card.Content> |
| 110 | + </Card> |
| 111 | + ); |
| 112 | + })} |
| 113 | + </div> |
| 114 | + </Flex> |
| 115 | + </div> |
109 | 116 | ); |
110 | 117 | } |
0 commit comments