rechta-ds 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.github/workflows/release.yml +53 -0
  3. package/.github/workflows/storybook.yml +34 -0
  4. package/.storybook/main.ts +17 -0
  5. package/.storybook/preview.ts +35 -0
  6. package/CHANGELOG.md +65 -0
  7. package/CONTRIBUTING.md +106 -0
  8. package/README.md +206 -0
  9. package/package.json +30 -0
  10. package/packages/tokens/build.js +357 -0
  11. package/packages/tokens/package.json +44 -0
  12. package/packages/tokens/src/tokens.json +1538 -0
  13. package/packages/ui/.storybook/main.ts +17 -0
  14. package/packages/ui/.storybook/preview.tsx +37 -0
  15. package/packages/ui/package.json +109 -0
  16. package/packages/ui/postcss.config.js +6 -0
  17. package/packages/ui/src/components/atoms/Avatar.tsx +139 -0
  18. package/packages/ui/src/components/atoms/Badge.tsx +62 -0
  19. package/packages/ui/src/components/atoms/Button.tsx +125 -0
  20. package/packages/ui/src/components/atoms/Input.tsx +116 -0
  21. package/packages/ui/src/components/atoms/Misc.tsx +128 -0
  22. package/packages/ui/src/components/atoms/Toggle.tsx +191 -0
  23. package/packages/ui/src/components/atoms/Typography.tsx +178 -0
  24. package/packages/ui/src/components/atoms/index.ts +7 -0
  25. package/packages/ui/src/components/charts/Charts.tsx +380 -0
  26. package/packages/ui/src/components/charts/DataTable.tsx +222 -0
  27. package/packages/ui/src/components/charts/index.ts +19 -0
  28. package/packages/ui/src/components/molecules/Accordion.tsx +93 -0
  29. package/packages/ui/src/components/molecules/Card.tsx +100 -0
  30. package/packages/ui/src/components/molecules/PricingCard.tsx +196 -0
  31. package/packages/ui/src/components/molecules/TestimonialCard.tsx +85 -0
  32. package/packages/ui/src/components/molecules/Tooltip.tsx +71 -0
  33. package/packages/ui/src/components/molecules/index.ts +5 -0
  34. package/packages/ui/src/components/organisms/FeatureTabs.tsx +196 -0
  35. package/packages/ui/src/components/organisms/LogoMarquee.tsx +119 -0
  36. package/packages/ui/src/components/organisms/Navbar.tsx +194 -0
  37. package/packages/ui/src/components/organisms/index.ts +3 -0
  38. package/packages/ui/src/index.ts +15 -0
  39. package/packages/ui/src/lib/utils.ts +12 -0
  40. package/packages/ui/src/stories/atoms/Avatar.stories.tsx +49 -0
  41. package/packages/ui/src/stories/atoms/Badge.stories.tsx +68 -0
  42. package/packages/ui/src/stories/atoms/Button.stories.tsx +98 -0
  43. package/packages/ui/src/stories/atoms/Input.stories.tsx +66 -0
  44. package/packages/ui/src/stories/atoms/Toggle.stories.tsx +36 -0
  45. package/packages/ui/src/stories/molecules/Accordion.stories.tsx +47 -0
  46. package/packages/ui/src/stories/molecules/Card.stories.tsx +84 -0
  47. package/packages/ui/src/stories/molecules/PricingCard.stories.tsx +62 -0
  48. package/packages/ui/src/stories/molecules/TestimonialCard.stories.tsx +52 -0
  49. package/packages/ui/src/stories/molecules/Tooltip.stories.tsx +66 -0
  50. package/packages/ui/src/stories/organisms/LogoMarquee.stories.tsx +33 -0
  51. package/packages/ui/src/stories/organisms/Navbar.stories.tsx +37 -0
  52. package/packages/ui/src/styles/globals.css +220 -0
  53. package/packages/ui/tailwind.config.ts +68 -0
  54. package/packages/ui/tsconfig.json +23 -0
  55. package/packages/ui/tsup.config.ts +24 -0
  56. package/packages/ui/vite.config.ts +17 -0
  57. package/pnpm-workspace.yaml +2 -0
  58. package/turbo.json +33 -0
@@ -0,0 +1,93 @@
1
+ import * as React from 'react';
2
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
3
+ import { ChevronDown } from 'lucide-react';
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const Accordion = AccordionPrimitive.Root;
7
+
8
+ const AccordionItem = React.forwardRef<
9
+ React.ElementRef<typeof AccordionPrimitive.Item>,
10
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
11
+ >(({ className, ...props }, ref) => (
12
+ <AccordionPrimitive.Item
13
+ ref={ref}
14
+ className={cn('border-b border-border last:border-0', className)}
15
+ {...props}
16
+ />
17
+ ));
18
+ AccordionItem.displayName = 'AccordionItem';
19
+
20
+ const AccordionTrigger = React.forwardRef<
21
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
22
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
23
+ >(({ className, children, ...props }, ref) => (
24
+ <AccordionPrimitive.Header className="flex">
25
+ <AccordionPrimitive.Trigger
26
+ ref={ref}
27
+ className={cn(
28
+ 'flex flex-1 items-center justify-between py-5 gap-4',
29
+ 'font-body font-medium text-text-primary text-left',
30
+ 'transition-all duration-200',
31
+ 'hover:text-text-primary/80',
32
+ '[&[data-state=open]>svg]:rotate-180',
33
+ 'focus-visible:outline-none focus-visible:text-text-brand',
34
+ 'group',
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ <span>{children}</span>
40
+ <ChevronDown className="size-4 text-text-tertiary shrink-0 transition-transform duration-300 ease-out group-hover:text-text-secondary" />
41
+ </AccordionPrimitive.Trigger>
42
+ </AccordionPrimitive.Header>
43
+ ));
44
+ AccordionTrigger.displayName = 'AccordionTrigger';
45
+
46
+ const AccordionContent = React.forwardRef<
47
+ React.ElementRef<typeof AccordionPrimitive.Content>,
48
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
49
+ >(({ className, children, ...props }, ref) => (
50
+ <AccordionPrimitive.Content
51
+ ref={ref}
52
+ className="overflow-hidden data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
53
+ {...props}
54
+ >
55
+ <div className={cn('pb-5 text-sm text-text-secondary leading-relaxed', className)}>
56
+ {children}
57
+ </div>
58
+ </AccordionPrimitive.Content>
59
+ ));
60
+ AccordionContent.displayName = 'AccordionContent';
61
+
62
+ // ─── FAQ block: self-contained FAQ section ────────────────────────────────────
63
+ export interface FAQItem {
64
+ question: string;
65
+ answer: React.ReactNode;
66
+ }
67
+
68
+ export interface FAQProps {
69
+ items: FAQItem[];
70
+ title?: string;
71
+ className?: string;
72
+ defaultOpen?: string[];
73
+ }
74
+
75
+ const FAQ: React.FC<FAQProps> = ({ items, title = 'Frequently asked questions', className, defaultOpen }) => (
76
+ <section className={cn('w-full', className)}>
77
+ {title && (
78
+ <h3 className="font-display text-2xl font-bold text-text-primary mb-8 tracking-tight">
79
+ {title}
80
+ </h3>
81
+ )}
82
+ <Accordion type="multiple" defaultValue={defaultOpen} className="w-full">
83
+ {items.map((item, i) => (
84
+ <AccordionItem key={i} value={`item-${i}`}>
85
+ <AccordionTrigger>{item.question}</AccordionTrigger>
86
+ <AccordionContent>{item.answer}</AccordionContent>
87
+ </AccordionItem>
88
+ ))}
89
+ </Accordion>
90
+ </section>
91
+ );
92
+
93
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent, FAQ };
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+ import { cn } from '../../lib/utils';
4
+
5
+ const cardVariants = cva(
6
+ ['rounded-xl border transition-all duration-200', 'relative overflow-hidden'],
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: 'bg-surface border-border',
11
+ raised: 'bg-surface-raised border-border shadow-md',
12
+ sunken: 'bg-surface-sunken border-border-subtle',
13
+ glass: 'bg-white/[0.03] border-white/[0.06] backdrop-blur-sm',
14
+ brand: 'bg-brand-500/5 border-brand-500/20',
15
+ accent: 'bg-accent-400/5 border-accent-400/20',
16
+ outline: 'bg-transparent border-border',
17
+ ghost: 'bg-transparent border-transparent',
18
+ },
19
+ hover: {
20
+ true: 'hover:border-border-strong hover:shadow-lg cursor-pointer',
21
+ false: '',
22
+ },
23
+ glow: {
24
+ none: '',
25
+ brand: 'shadow-glow-brand',
26
+ accent: 'shadow-glow-accent',
27
+ },
28
+ padding: {
29
+ none: 'p-0',
30
+ sm: 'p-4',
31
+ md: 'p-6',
32
+ lg: 'p-8',
33
+ xl: 'p-10',
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: 'default',
38
+ hover: false,
39
+ glow: 'none',
40
+ padding: 'md',
41
+ },
42
+ }
43
+ );
44
+
45
+ export interface CardProps
46
+ extends React.HTMLAttributes<HTMLDivElement>,
47
+ VariantProps<typeof cardVariants> {}
48
+
49
+ const Card = React.forwardRef<HTMLDivElement, CardProps>(
50
+ ({ className, variant, hover, glow, padding, ...props }, ref) => (
51
+ <div
52
+ ref={ref}
53
+ className={cn(cardVariants({ variant, hover, glow, padding, className }))}
54
+ {...props}
55
+ />
56
+ )
57
+ );
58
+ Card.displayName = 'Card';
59
+
60
+ // Sub-components
61
+ const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
62
+ ({ className, ...props }, ref) => (
63
+ <div ref={ref} className={cn('flex flex-col gap-1.5', className)} {...props} />
64
+ )
65
+ );
66
+ CardHeader.displayName = 'CardHeader';
67
+
68
+ const CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
69
+ ({ className, ...props }, ref) => (
70
+ <h3
71
+ ref={ref}
72
+ className={cn('font-display font-semibold text-text-primary leading-tight tracking-tight', className)}
73
+ {...props}
74
+ />
75
+ )
76
+ );
77
+ CardTitle.displayName = 'CardTitle';
78
+
79
+ const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
80
+ ({ className, ...props }, ref) => (
81
+ <p ref={ref} className={cn('text-sm text-text-secondary leading-relaxed', className)} {...props} />
82
+ )
83
+ );
84
+ CardDescription.displayName = 'CardDescription';
85
+
86
+ const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
87
+ ({ className, ...props }, ref) => (
88
+ <div ref={ref} className={cn('', className)} {...props} />
89
+ )
90
+ );
91
+ CardContent.displayName = 'CardContent';
92
+
93
+ const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
94
+ ({ className, ...props }, ref) => (
95
+ <div ref={ref} className={cn('flex items-center gap-3 pt-4 border-t border-border mt-4', className)} {...props} />
96
+ )
97
+ );
98
+ CardFooter.displayName = 'CardFooter';
99
+
100
+ export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, cardVariants };
@@ -0,0 +1,196 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../../lib/utils';
3
+ import { Button } from '../atoms/Button';
4
+ import { Badge } from '../atoms/Badge';
5
+ import { Separator } from '../atoms/Misc';
6
+ import { Check } from 'lucide-react';
7
+
8
+ export interface PricingLimitRow {
9
+ label: string;
10
+ value: string;
11
+ tooltip?: string;
12
+ }
13
+
14
+ export interface PricingFeature {
15
+ text: string;
16
+ highlight?: boolean;
17
+ integration?: 'shopify' | string;
18
+ }
19
+
20
+ export interface PricingCardProps extends React.HTMLAttributes<HTMLDivElement> {
21
+ planName: string;
22
+ description: string;
23
+ price: number | 'custom';
24
+ originalPrice?: number;
25
+ billingPeriod?: 'monthly' | 'yearly';
26
+ annualTotal?: string;
27
+ savingsPercent?: number;
28
+ ctaLabel: string;
29
+ ctaVariant?: 'default' | 'secondary' | 'outline';
30
+ onCtaClick?: () => void;
31
+ limits?: PricingLimitRow[];
32
+ features?: PricingFeature[];
33
+ sectionLabel?: string;
34
+ recommended?: boolean;
35
+ support?: string;
36
+ }
37
+
38
+ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
39
+ ({
40
+ className,
41
+ planName,
42
+ description,
43
+ price,
44
+ originalPrice,
45
+ billingPeriod = 'monthly',
46
+ annualTotal,
47
+ savingsPercent,
48
+ ctaLabel,
49
+ ctaVariant = 'secondary',
50
+ onCtaClick,
51
+ limits = [],
52
+ features = [],
53
+ sectionLabel,
54
+ recommended = false,
55
+ support,
56
+ ...props
57
+ }, ref) => {
58
+ return (
59
+ <div
60
+ ref={ref}
61
+ className={cn(
62
+ 'relative flex flex-col rounded-2xl border transition-all duration-300',
63
+ recommended
64
+ ? 'bg-brand-500/5 border-brand-500/40 shadow-glow-brand'
65
+ : 'bg-surface border-border hover:border-border-strong',
66
+ className
67
+ )}
68
+ {...props}
69
+ >
70
+ {/* Recommended ribbon */}
71
+ {recommended && (
72
+ <div className="absolute -top-3.5 left-1/2 -translate-x-1/2">
73
+ <Badge variant="solid" className="shadow-md px-3">
74
+ Recommended
75
+ </Badge>
76
+ </div>
77
+ )}
78
+
79
+ <div className="p-7 flex flex-col gap-5 flex-1">
80
+ {/* Header */}
81
+ <div className="flex flex-col gap-2">
82
+ <h3 className="font-display text-xl font-bold text-text-primary">{planName}</h3>
83
+ <p className="text-sm text-text-tertiary leading-relaxed">{description}</p>
84
+ </div>
85
+
86
+ {/* Price */}
87
+ <div className="flex flex-col gap-1">
88
+ <div className="flex items-baseline gap-2 flex-wrap">
89
+ {price === 'custom' ? (
90
+ <span className="font-display text-4xl font-bold text-text-primary tracking-tight">
91
+ Custom
92
+ </span>
93
+ ) : (
94
+ <>
95
+ {originalPrice && (
96
+ <span className="font-mono text-xl text-text-tertiary line-through">
97
+ ${originalPrice}
98
+ </span>
99
+ )}
100
+ <span className="font-display text-4xl font-bold text-text-primary tracking-tight">
101
+ ${price}
102
+ </span>
103
+ <div className="flex items-center gap-1.5">
104
+ <span className="text-sm text-text-tertiary">/{billingPeriod === 'monthly' ? 'mo' : 'yr'}</span>
105
+ {savingsPercent && (
106
+ <Badge variant="brand">-{savingsPercent}%</Badge>
107
+ )}
108
+ </div>
109
+ </>
110
+ )}
111
+ </div>
112
+ {annualTotal && (
113
+ <span className="text-xs font-mono text-text-tertiary">{annualTotal}</span>
114
+ )}
115
+ </div>
116
+
117
+ {/* CTA */}
118
+ <Button
119
+ variant={recommended ? 'default' : ctaVariant}
120
+ size="md"
121
+ className="w-full"
122
+ onClick={onCtaClick}
123
+ >
124
+ {ctaLabel}
125
+ </Button>
126
+
127
+ <Separator variant="subtle" />
128
+
129
+ {/* Limits */}
130
+ {limits.length > 0 && (
131
+ <div className="flex flex-col gap-3">
132
+ {limits.map((limit, i) => (
133
+ <div key={i} className="flex items-start justify-between gap-4">
134
+ <div className="flex flex-col gap-0.5 min-w-0">
135
+ <span className="text-sm font-medium text-text-primary">{limit.value}</span>
136
+ {limit.tooltip && (
137
+ <span className="text-xs text-text-tertiary leading-snug">{limit.tooltip}</span>
138
+ )}
139
+ </div>
140
+ <span className="text-xs font-mono text-text-tertiary whitespace-nowrap shrink-0 mt-0.5 text-right">
141
+ {limit.label}
142
+ </span>
143
+ </div>
144
+ ))}
145
+ </div>
146
+ )}
147
+
148
+ <Separator variant="subtle" />
149
+
150
+ {/* Features */}
151
+ {features.length > 0 && (
152
+ <div className="flex flex-col gap-2.5">
153
+ {sectionLabel && (
154
+ <p className="text-xs font-mono text-text-tertiary tracking-wider uppercase mb-1">
155
+ {sectionLabel}
156
+ </p>
157
+ )}
158
+ {features.map((feature, i) => (
159
+ <div key={i} className="flex items-start gap-2.5">
160
+ <Check className={cn(
161
+ 'size-4 shrink-0 mt-0.5',
162
+ feature.highlight ? 'text-brand-400' : 'text-text-tertiary'
163
+ )} />
164
+ <span className={cn(
165
+ 'text-sm leading-snug',
166
+ feature.highlight ? 'text-text-primary font-medium' : 'text-text-secondary'
167
+ )}>
168
+ {feature.integration === 'shopify' && (
169
+ <span className="inline-flex items-center gap-1 text-[10px] font-mono text-text-tertiary border border-border rounded px-1 mr-1.5 py-px">
170
+ SHOPIFY
171
+ </span>
172
+ )}
173
+ {feature.text}
174
+ </span>
175
+ </div>
176
+ ))}
177
+ </div>
178
+ )}
179
+
180
+ {/* Support */}
181
+ {support && (
182
+ <div className="mt-auto pt-3 border-t border-border">
183
+ <p className="text-xs text-text-tertiary leading-snug">
184
+ <span className="font-medium text-text-secondary">Support: </span>
185
+ {support}
186
+ </p>
187
+ </div>
188
+ )}
189
+ </div>
190
+ </div>
191
+ );
192
+ }
193
+ );
194
+ PricingCard.displayName = 'PricingCard';
195
+
196
+ export { PricingCard };
@@ -0,0 +1,85 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../../lib/utils';
3
+ import { Avatar } from '../atoms/Avatar';
4
+ import { StarRating } from '../atoms/Misc';
5
+
6
+ export interface TestimonialCardProps extends React.HTMLAttributes<HTMLDivElement> {
7
+ quote: string;
8
+ authorName: string;
9
+ authorTitle: string;
10
+ authorAvatar?: string;
11
+ companyLogo?: string;
12
+ companyName?: string;
13
+ rating?: number;
14
+ featured?: boolean;
15
+ }
16
+
17
+ const TestimonialCard = React.forwardRef<HTMLDivElement, TestimonialCardProps>(
18
+ ({
19
+ className,
20
+ quote,
21
+ authorName,
22
+ authorTitle,
23
+ authorAvatar,
24
+ companyLogo,
25
+ companyName,
26
+ rating,
27
+ featured = false,
28
+ ...props
29
+ }, ref) => {
30
+ return (
31
+ <div
32
+ ref={ref}
33
+ className={cn(
34
+ 'relative flex flex-col gap-5 rounded-xl border p-6 transition-all duration-300',
35
+ featured
36
+ ? 'bg-brand-500/5 border-brand-500/30 hover:border-brand-500/50 hover:shadow-glow-brand'
37
+ : 'bg-surface border-border hover:border-border-strong hover:bg-surface-raised',
38
+ className
39
+ )}
40
+ {...props}
41
+ >
42
+ {/* Quote mark */}
43
+ <span className="font-editorial text-5xl leading-none text-brand-500/20 select-none absolute top-4 right-6">
44
+ "
45
+ </span>
46
+
47
+ {/* Company logo */}
48
+ {companyLogo && (
49
+ <div className="flex items-center">
50
+ <img
51
+ src={companyLogo}
52
+ alt={companyName ?? ''}
53
+ className="h-6 object-contain opacity-60 filter brightness-200"
54
+ />
55
+ </div>
56
+ )}
57
+
58
+ {/* Rating */}
59
+ {rating && <StarRating value={rating} showValue size="sm" />}
60
+
61
+ {/* Quote */}
62
+ <blockquote className="text-sm text-text-secondary leading-relaxed flex-1">
63
+ "{quote}"
64
+ </blockquote>
65
+
66
+ {/* Author */}
67
+ <div className="flex items-center gap-3 pt-2 border-t border-border">
68
+ <Avatar
69
+ src={authorAvatar}
70
+ fallback={authorName.slice(0, 2)}
71
+ alt={authorName}
72
+ size="sm"
73
+ />
74
+ <div className="flex flex-col min-w-0">
75
+ <span className="text-sm font-semibold text-text-primary truncate">{authorName}</span>
76
+ <span className="text-xs text-text-tertiary truncate">{authorTitle}</span>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ );
81
+ }
82
+ );
83
+ TestimonialCard.displayName = 'TestimonialCard';
84
+
85
+ export { TestimonialCard };
@@ -0,0 +1,71 @@
1
+ import * as React from 'react';
2
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
3
+ import { cn } from '../../lib/utils';
4
+
5
+ const TooltipProvider = TooltipPrimitive.Provider;
6
+ const TooltipRoot = TooltipPrimitive.Root;
7
+ const TooltipTrigger = TooltipPrimitive.Trigger;
8
+
9
+ const TooltipContent = React.forwardRef<
10
+ React.ElementRef<typeof TooltipPrimitive.Content>,
11
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {
12
+ variant?: 'default' | 'brand' | 'accent';
13
+ }
14
+ >(({ className, sideOffset = 6, variant = 'default', ...props }, ref) => (
15
+ <TooltipPrimitive.Portal>
16
+ <TooltipPrimitive.Content
17
+ ref={ref}
18
+ sideOffset={sideOffset}
19
+ className={cn(
20
+ 'z-tooltip overflow-hidden rounded-lg border px-3 py-1.5',
21
+ 'text-xs font-body leading-normal',
22
+ 'animate-scale-in',
23
+ 'shadow-lg',
24
+ {
25
+ default: 'bg-surface-raised border-border text-text-primary',
26
+ brand: 'bg-brand-500 border-brand-500 text-gray-950',
27
+ accent: 'bg-accent-400 border-accent-400 text-gray-950',
28
+ }[variant],
29
+ className
30
+ )}
31
+ {...props}
32
+ >
33
+ {props.children}
34
+ <TooltipPrimitive.Arrow
35
+ className={cn(
36
+ 'fill-current',
37
+ variant === 'default' ? 'text-surface-raised' : variant === 'brand' ? 'text-brand-500' : 'text-accent-400'
38
+ )}
39
+ width={8}
40
+ height={4}
41
+ />
42
+ </TooltipPrimitive.Content>
43
+ </TooltipPrimitive.Portal>
44
+ ));
45
+ TooltipContent.displayName = 'TooltipContent';
46
+
47
+ // ─── Convenience wrapper ──────────────────────────────────────────────────────
48
+ export interface TooltipProps {
49
+ content: React.ReactNode;
50
+ children: React.ReactNode;
51
+ side?: 'top' | 'right' | 'bottom' | 'left';
52
+ variant?: 'default' | 'brand' | 'accent';
53
+ delayDuration?: number;
54
+ }
55
+
56
+ const Tooltip: React.FC<TooltipProps> = ({
57
+ content,
58
+ children,
59
+ side = 'top',
60
+ variant = 'default',
61
+ delayDuration = 300,
62
+ }) => (
63
+ <TooltipProvider delayDuration={delayDuration}>
64
+ <TooltipRoot>
65
+ <TooltipTrigger asChild>{children}</TooltipTrigger>
66
+ <TooltipContent side={side} variant={variant}>{content}</TooltipContent>
67
+ </TooltipRoot>
68
+ </TooltipProvider>
69
+ );
70
+
71
+ export { Tooltip, TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent };
@@ -0,0 +1,5 @@
1
+ export * from './Card';
2
+ export * from './Accordion';
3
+ export * from './PricingCard';
4
+ export * from './TestimonialCard';
5
+ export * from './Tooltip';