@sudobility/marketing-components-rn 1.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 (42) hide show
  1. package/dist/CrmDashboard.d.ts +12 -0
  2. package/dist/CrmDashboard.d.ts.map +1 -0
  3. package/dist/CtaBanner.d.ts +13 -0
  4. package/dist/CtaBanner.d.ts.map +1 -0
  5. package/dist/FeatureListItem.d.ts +13 -0
  6. package/dist/FeatureListItem.d.ts.map +1 -0
  7. package/dist/FeatureSpotlight.d.ts +13 -0
  8. package/dist/FeatureSpotlight.d.ts.map +1 -0
  9. package/dist/HeroBannerWithBadge.d.ts +27 -0
  10. package/dist/HeroBannerWithBadge.d.ts.map +1 -0
  11. package/dist/InternalLinkClusters.d.ts +33 -0
  12. package/dist/InternalLinkClusters.d.ts.map +1 -0
  13. package/dist/NpsSurvey.d.ts +13 -0
  14. package/dist/NpsSurvey.d.ts.map +1 -0
  15. package/dist/SalesReport.d.ts +12 -0
  16. package/dist/SalesReport.d.ts.map +1 -0
  17. package/dist/TestimonialSlider.d.ts +13 -0
  18. package/dist/TestimonialSlider.d.ts.map +1 -0
  19. package/dist/UseCaseGrid.d.ts +23 -0
  20. package/dist/UseCaseGrid.d.ts.map +1 -0
  21. package/dist/WelcomeScreen.d.ts +17 -0
  22. package/dist/WelcomeScreen.d.ts.map +1 -0
  23. package/dist/index.cjs.js +1459 -0
  24. package/dist/index.cjs.js.map +1 -0
  25. package/dist/index.d.ts +16 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.esm.js +1459 -0
  28. package/dist/index.esm.js.map +1 -0
  29. package/package.json +56 -0
  30. package/src/CrmDashboard.tsx +39 -0
  31. package/src/CtaBanner.tsx +46 -0
  32. package/src/FeatureListItem.tsx +47 -0
  33. package/src/FeatureSpotlight.tsx +46 -0
  34. package/src/HeroBannerWithBadge.tsx +134 -0
  35. package/src/InternalLinkClusters.tsx +193 -0
  36. package/src/NpsSurvey.tsx +46 -0
  37. package/src/SalesReport.tsx +39 -0
  38. package/src/TestimonialSlider.tsx +46 -0
  39. package/src/UseCaseGrid.tsx +128 -0
  40. package/src/WelcomeScreen.tsx +82 -0
  41. package/src/index.ts +32 -0
  42. package/src/nativewind.d.ts +23 -0
@@ -0,0 +1,193 @@
1
+ import React from 'react';
2
+ import { View, Text, Pressable, type ViewProps } from 'react-native';
3
+ import { cn } from '@sudobility/components-rn';
4
+
5
+ export interface InternalLinkProps {
6
+ to: string;
7
+ children: React.ReactNode;
8
+ className?: string;
9
+ variant?: 'primary' | 'secondary' | 'subtle';
10
+ onPress?: (url: string) => void;
11
+ }
12
+
13
+ const linkVariants = {
14
+ primary: 'text-blue-600 dark:text-blue-400',
15
+ secondary: 'text-green-600 dark:text-green-400',
16
+ subtle: 'text-gray-600 dark:text-gray-400',
17
+ };
18
+
19
+ export const InternalLink: React.FC<InternalLinkProps> = ({
20
+ to,
21
+ children,
22
+ className,
23
+ variant = 'primary',
24
+ onPress,
25
+ }) => (
26
+ <Pressable
27
+ onPress={() => onPress?.(to)}
28
+ accessibilityRole="link"
29
+ accessibilityLabel={typeof children === 'string' ? `Navigate to ${children}` : undefined}
30
+ >
31
+ <Text className={cn('underline font-medium', linkVariants[variant], className)}>
32
+ {children}
33
+ </Text>
34
+ </Pressable>
35
+ );
36
+
37
+ type ClusterType = 'gettingStarted' | 'benefits' | 'technical' | 'integration';
38
+
39
+ export interface TopicClusterLinksProps extends ViewProps {
40
+ cluster: ClusterType;
41
+ context?: string;
42
+ onLinkPress?: (url: string) => void;
43
+ }
44
+
45
+ const WEB3_EMAIL_CLUSTERS: Record<ClusterType, Record<string, string>> = {
46
+ gettingStarted: {
47
+ documentation: '/document#getting-started',
48
+ connect: '/connect',
49
+ features: '/document#email-management',
50
+ },
51
+ benefits: {
52
+ users: '/web3-users',
53
+ projects: '/web3-projects',
54
+ security: '/document#technical-details',
55
+ nameService: '/document#name-service-subscription',
56
+ },
57
+ technical: {
58
+ documentation: '/document',
59
+ apiDocs: '/document#api-documentation',
60
+ smartContracts: '/document#smart-contracts',
61
+ security: '/document#technical-details',
62
+ },
63
+ integration: {
64
+ projects: '/web3-projects',
65
+ delegation: '/document#email-delegation',
66
+ nameService: '/document#name-service-subscription',
67
+ troubleshooting: '/document#troubleshooting',
68
+ },
69
+ };
70
+
71
+ const LINK_TEXTS: Record<ClusterType, Record<string, string>> = {
72
+ gettingStarted: {
73
+ documentation: 'Learn how it works',
74
+ connect: 'Get started now',
75
+ features: 'Explore features',
76
+ },
77
+ benefits: {
78
+ users: 'Benefits for users',
79
+ projects: 'For Web3 projects',
80
+ security: 'Security details',
81
+ nameService: 'ENS/SNS domains',
82
+ },
83
+ technical: {
84
+ documentation: 'Full documentation',
85
+ apiDocs: 'API reference',
86
+ smartContracts: 'Smart contract integration',
87
+ security: 'Technical security',
88
+ },
89
+ integration: {
90
+ projects: 'Integration examples',
91
+ delegation: 'Email delegation',
92
+ nameService: 'Domain setup',
93
+ troubleshooting: 'Troubleshooting guide',
94
+ },
95
+ };
96
+
97
+ export const TopicClusterLinks: React.FC<TopicClusterLinksProps> = ({
98
+ cluster,
99
+ className,
100
+ onLinkPress,
101
+ ...props
102
+ }) => {
103
+ const links = WEB3_EMAIL_CLUSTERS[cluster];
104
+ const texts = LINK_TEXTS[cluster];
105
+
106
+ return (
107
+ <View className={cn('flex-row flex-wrap gap-2', className)} {...props}>
108
+ {Object.entries(links).map(([key, url], index) => (
109
+ <React.Fragment key={key}>
110
+ <InternalLink to={url} variant="primary" onPress={onLinkPress}>
111
+ {texts[key]}
112
+ </InternalLink>
113
+ {index < Object.keys(links).length - 1 && (
114
+ <Text className="text-gray-400"> • </Text>
115
+ )}
116
+ </React.Fragment>
117
+ ))}
118
+ </View>
119
+ );
120
+ };
121
+
122
+ export interface RelatedLinksProps extends ViewProps {
123
+ title?: string;
124
+ links: Array<{
125
+ text: string;
126
+ url: string;
127
+ variant?: 'primary' | 'secondary' | 'subtle';
128
+ }>;
129
+ onLinkPress?: (url: string) => void;
130
+ }
131
+
132
+ export const RelatedLinks: React.FC<RelatedLinksProps> = ({
133
+ title = 'Related:',
134
+ links,
135
+ className,
136
+ onLinkPress,
137
+ ...props
138
+ }) => (
139
+ <View
140
+ className={cn(
141
+ 'mt-4 p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800',
142
+ className
143
+ )}
144
+ {...props}
145
+ >
146
+ <View className="flex-row flex-wrap items-center gap-2">
147
+ <Text className="text-sm font-medium text-blue-900 dark:text-blue-200">
148
+ {title}
149
+ </Text>
150
+ {links.map((link, index) => (
151
+ <React.Fragment key={index}>
152
+ <InternalLink
153
+ to={link.url}
154
+ variant={link.variant || 'primary'}
155
+ onPress={onLinkPress}
156
+ >
157
+ {link.text}
158
+ </InternalLink>
159
+ {index < links.length - 1 && (
160
+ <Text className="text-gray-400"> • </Text>
161
+ )}
162
+ </React.Fragment>
163
+ ))}
164
+ </View>
165
+ </View>
166
+ );
167
+
168
+ export const generateContextualLinks = (pageType: string, _userStatus?: string) => {
169
+ const baseLinks: Record<string, Array<{ text: string; url: string }>> = {
170
+ homepage: [
171
+ { text: 'How it works', url: '/document#getting-started' },
172
+ { text: 'User benefits', url: '/web3-users' },
173
+ { text: 'For projects', url: '/web3-projects' },
174
+ ],
175
+ documentation: [
176
+ { text: 'Get started', url: '/connect' },
177
+ { text: 'User guide', url: '/web3-users' },
178
+ { text: 'API docs', url: '/document#api-documentation' },
179
+ ],
180
+ users: [
181
+ { text: 'Start now', url: '/connect' },
182
+ { text: 'Documentation', url: '/document' },
183
+ { text: 'For projects', url: '/web3-projects' },
184
+ ],
185
+ projects: [
186
+ { text: 'API integration', url: '/document#api-documentation' },
187
+ { text: 'Smart contracts', url: '/document#smart-contracts' },
188
+ { text: 'User benefits', url: '/web3-users' },
189
+ ],
190
+ };
191
+
192
+ return baseLinks[pageType] || [];
193
+ };
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { Text, Pressable, type ViewProps } from 'react-native';
3
+ import { cn } from '@sudobility/components-rn';
4
+
5
+ export interface NpsSurveyProps extends ViewProps {
6
+ disabled?: boolean;
7
+ onPress?: () => void;
8
+ children?: React.ReactNode;
9
+ }
10
+
11
+ /**
12
+ * NpsSurvey component for React Native
13
+ * NPS survey display
14
+ */
15
+ export const NpsSurvey: React.FC<NpsSurveyProps> = ({
16
+ className,
17
+ children,
18
+ disabled = false,
19
+ onPress,
20
+ ...props
21
+ }) => {
22
+ return (
23
+ <Pressable
24
+ onPress={disabled ? undefined : onPress}
25
+ disabled={disabled}
26
+ accessibilityRole="button"
27
+ accessibilityLabel="NPS Survey"
28
+ accessibilityState={{ disabled }}
29
+ className={cn(
30
+ 'p-4 rounded-lg border',
31
+ 'bg-white dark:bg-gray-900',
32
+ 'border-gray-200 dark:border-gray-700',
33
+ disabled && 'opacity-50',
34
+ 'active:bg-gray-50 dark:active:bg-gray-800',
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ {children || (
40
+ <Text className="text-gray-900 dark:text-white">
41
+ NpsSurvey Component
42
+ </Text>
43
+ )}
44
+ </Pressable>
45
+ );
46
+ };
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { View, Text, type ViewProps } from 'react-native';
3
+ import { cn } from '@sudobility/components-rn';
4
+
5
+ export interface SalesReportProps extends ViewProps {
6
+ disabled?: boolean;
7
+ children?: React.ReactNode;
8
+ }
9
+
10
+ /**
11
+ * SalesReport component for React Native
12
+ * Sales report display container
13
+ */
14
+ export const SalesReport: React.FC<SalesReportProps> = ({
15
+ className,
16
+ children,
17
+ disabled,
18
+ ...props
19
+ }) => {
20
+ return (
21
+ <View
22
+ className={cn(
23
+ 'p-4 rounded-lg border',
24
+ 'bg-white dark:bg-gray-900',
25
+ 'border-gray-200 dark:border-gray-700',
26
+ disabled && 'opacity-50',
27
+ className
28
+ )}
29
+ accessibilityLabel="Sales Report"
30
+ {...props}
31
+ >
32
+ {children || (
33
+ <Text className="text-gray-900 dark:text-white">
34
+ SalesReport Component
35
+ </Text>
36
+ )}
37
+ </View>
38
+ );
39
+ };
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { Text, Pressable, type ViewProps } from 'react-native';
3
+ import { cn } from '@sudobility/components-rn';
4
+
5
+ export interface TestimonialSliderProps extends ViewProps {
6
+ disabled?: boolean;
7
+ onPress?: () => void;
8
+ children?: React.ReactNode;
9
+ }
10
+
11
+ /**
12
+ * TestimonialSlider component for React Native
13
+ * Testimonial slider display
14
+ */
15
+ export const TestimonialSlider: React.FC<TestimonialSliderProps> = ({
16
+ className,
17
+ children,
18
+ disabled = false,
19
+ onPress,
20
+ ...props
21
+ }) => {
22
+ return (
23
+ <Pressable
24
+ onPress={disabled ? undefined : onPress}
25
+ disabled={disabled}
26
+ accessibilityRole="button"
27
+ accessibilityLabel="Testimonial Slider"
28
+ accessibilityState={{ disabled }}
29
+ className={cn(
30
+ 'p-4 rounded-lg border',
31
+ 'bg-white dark:bg-gray-900',
32
+ 'border-gray-200 dark:border-gray-700',
33
+ disabled && 'opacity-50',
34
+ 'active:bg-gray-50 dark:active:bg-gray-800',
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ {children || (
40
+ <Text className="text-gray-900 dark:text-white">
41
+ TestimonialSlider Component
42
+ </Text>
43
+ )}
44
+ </Pressable>
45
+ );
46
+ };
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+ import { View, Text, FlatList, type ViewProps } from 'react-native';
3
+ import { cn } from '@sudobility/components-rn';
4
+
5
+ type UseCaseColor = 'blue' | 'green' | 'purple' | 'orange' | 'pink' | 'gray';
6
+
7
+ export interface UseCase {
8
+ icon: React.ReactNode;
9
+ title: string;
10
+ description: string;
11
+ examples: string[];
12
+ color?: UseCaseColor;
13
+ }
14
+
15
+ export interface UseCaseGridProps extends ViewProps {
16
+ title?: string;
17
+ description?: string;
18
+ useCases: UseCase[];
19
+ columns?: 2 | 3 | 4;
20
+ }
21
+
22
+ const colorClasses: Record<UseCaseColor, string> = {
23
+ blue: 'text-blue-600 dark:text-blue-400',
24
+ green: 'text-green-600 dark:text-green-400',
25
+ purple: 'text-purple-600 dark:text-purple-400',
26
+ orange: 'text-orange-600 dark:text-orange-400',
27
+ pink: 'text-pink-600 dark:text-pink-400',
28
+ gray: 'text-gray-600 dark:text-gray-400',
29
+ };
30
+
31
+ const bulletColors: Record<UseCaseColor, string> = {
32
+ blue: 'bg-blue-500',
33
+ green: 'bg-green-500',
34
+ purple: 'bg-purple-500',
35
+ orange: 'bg-orange-500',
36
+ pink: 'bg-pink-500',
37
+ gray: 'bg-gray-500',
38
+ };
39
+
40
+ interface UseCaseCardProps {
41
+ useCase: UseCase;
42
+ }
43
+
44
+ const UseCaseCard: React.FC<UseCaseCardProps> = ({ useCase }) => {
45
+ const iconColor = useCase.color ? colorClasses[useCase.color] : colorClasses.blue;
46
+ const bulletColor = useCase.color ? bulletColors[useCase.color] : bulletColors.blue;
47
+
48
+ return (
49
+ <View className="bg-white dark:bg-gray-800 rounded-xl p-6 border border-gray-200 dark:border-gray-700 mb-4 mx-2">
50
+ <View className={cn('mb-4', iconColor)}>{useCase.icon}</View>
51
+
52
+ <Text className="text-xl font-semibold text-gray-900 dark:text-white mb-3">
53
+ {useCase.title}
54
+ </Text>
55
+
56
+ <Text className="text-gray-600 dark:text-gray-300 mb-4">
57
+ {useCase.description}
58
+ </Text>
59
+
60
+ {useCase.examples && useCase.examples.length > 0 && (
61
+ <View>
62
+ <Text className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
63
+ Examples:
64
+ </Text>
65
+ <View className="gap-1">
66
+ {useCase.examples.map((example, exampleIndex) => (
67
+ <View key={exampleIndex} className="flex-row items-start">
68
+ <View
69
+ className={cn(
70
+ 'w-1.5 h-1.5 rounded-full mt-2 mr-2',
71
+ bulletColor
72
+ )}
73
+ />
74
+ <Text className="text-sm text-gray-600 dark:text-gray-400 flex-1">
75
+ {example}
76
+ </Text>
77
+ </View>
78
+ ))}
79
+ </View>
80
+ </View>
81
+ )}
82
+ </View>
83
+ );
84
+ };
85
+
86
+ /**
87
+ * UseCaseGrid component for React Native
88
+ * Grid display of use cases
89
+ */
90
+ export const UseCaseGrid: React.FC<UseCaseGridProps> = ({
91
+ title,
92
+ description,
93
+ useCases,
94
+ columns = 2,
95
+ className,
96
+ ...props
97
+ }) => {
98
+ return (
99
+ <View className={cn('py-8 px-4', className)} {...props}>
100
+ {(title || description) && (
101
+ <View className="items-center mb-8">
102
+ {title && (
103
+ <Text className="text-2xl font-bold text-gray-900 dark:text-white mb-4 text-center">
104
+ {title}
105
+ </Text>
106
+ )}
107
+ {description && (
108
+ <Text className="text-lg text-gray-600 dark:text-gray-300 text-center max-w-lg">
109
+ {description}
110
+ </Text>
111
+ )}
112
+ </View>
113
+ )}
114
+
115
+ <FlatList
116
+ data={useCases}
117
+ keyExtractor={(_, index) => index.toString()}
118
+ numColumns={columns > 2 ? 2 : columns}
119
+ renderItem={({ item }) => (
120
+ <View className={columns > 2 ? 'flex-1' : 'flex-1'}>
121
+ <UseCaseCard useCase={item} />
122
+ </View>
123
+ )}
124
+ scrollEnabled={false}
125
+ />
126
+ </View>
127
+ );
128
+ };
@@ -0,0 +1,82 @@
1
+ import React from 'react';
2
+ import { View, Text, type ViewProps } from 'react-native';
3
+ import { cn, Button } from '@sudobility/components-rn';
4
+
5
+ export interface WelcomeScreenProps extends ViewProps {
6
+ title: string;
7
+ subtitle?: string;
8
+ description?: string;
9
+ illustration?: React.ReactNode;
10
+ primaryButtonText?: string;
11
+ secondaryButtonText?: string;
12
+ onPrimaryPress?: () => void;
13
+ onSecondaryPress?: () => void;
14
+ }
15
+
16
+ /**
17
+ * Welcome screen component for onboarding flows
18
+ */
19
+ export const WelcomeScreen: React.FC<WelcomeScreenProps> = ({
20
+ title,
21
+ subtitle,
22
+ description,
23
+ illustration,
24
+ primaryButtonText = 'Get Started',
25
+ secondaryButtonText,
26
+ onPrimaryPress,
27
+ onSecondaryPress,
28
+ className,
29
+ ...props
30
+ }) => {
31
+ return (
32
+ <View
33
+ className={cn(
34
+ 'flex-1 items-center justify-center px-6 py-12',
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ {illustration && (
40
+ <View className="mb-8">{illustration}</View>
41
+ )}
42
+
43
+ {subtitle && (
44
+ <Text className="text-sm font-medium text-blue-600 dark:text-blue-400 mb-2 uppercase tracking-wide">
45
+ {subtitle}
46
+ </Text>
47
+ )}
48
+
49
+ <Text className="text-3xl font-bold text-gray-900 dark:text-white text-center mb-4">
50
+ {title}
51
+ </Text>
52
+
53
+ {description && (
54
+ <Text className="text-base text-gray-600 dark:text-gray-400 text-center mb-8 max-w-sm">
55
+ {description}
56
+ </Text>
57
+ )}
58
+
59
+ <View className="w-full max-w-xs gap-3">
60
+ <Button
61
+ variant="primary"
62
+ size="lg"
63
+ onPress={onPrimaryPress}
64
+ className="w-full"
65
+ >
66
+ {primaryButtonText}
67
+ </Button>
68
+
69
+ {secondaryButtonText && (
70
+ <Button
71
+ variant="ghost"
72
+ size="lg"
73
+ onPress={onSecondaryPress}
74
+ className="w-full"
75
+ >
76
+ {secondaryButtonText}
77
+ </Button>
78
+ )}
79
+ </View>
80
+ </View>
81
+ );
82
+ };
package/src/index.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @sudobility/marketing-components-rn
3
+ * React Native Marketing components for Sudobility
4
+ */
5
+
6
+ export { CrmDashboard, type CrmDashboardProps } from './CrmDashboard';
7
+ export { CtaBanner, type CtaBannerProps } from './CtaBanner';
8
+ export { FeatureListItem, type FeatureListItemProps } from './FeatureListItem';
9
+ export { FeatureSpotlight, type FeatureSpotlightProps } from './FeatureSpotlight';
10
+ export {
11
+ HeroBannerWithBadge,
12
+ type HeroBannerWithBadgeProps,
13
+ type ButtonConfig,
14
+ } from './HeroBannerWithBadge';
15
+ export {
16
+ InternalLink,
17
+ TopicClusterLinks,
18
+ RelatedLinks,
19
+ generateContextualLinks,
20
+ type InternalLinkProps,
21
+ type TopicClusterLinksProps,
22
+ type RelatedLinksProps,
23
+ } from './InternalLinkClusters';
24
+ export { NpsSurvey, type NpsSurveyProps } from './NpsSurvey';
25
+ export { SalesReport, type SalesReportProps } from './SalesReport';
26
+ export { TestimonialSlider, type TestimonialSliderProps } from './TestimonialSlider';
27
+ export {
28
+ UseCaseGrid,
29
+ type UseCaseGridProps,
30
+ type UseCase,
31
+ } from './UseCaseGrid';
32
+ export { WelcomeScreen, type WelcomeScreenProps } from './WelcomeScreen';
@@ -0,0 +1,23 @@
1
+ // Type declarations for NativeWind className prop
2
+ import 'react-native';
3
+
4
+ declare module 'react-native' {
5
+ interface ViewProps {
6
+ className?: string;
7
+ }
8
+ interface TextProps {
9
+ className?: string;
10
+ }
11
+ interface ImageProps {
12
+ className?: string;
13
+ }
14
+ interface PressableProps {
15
+ className?: string;
16
+ }
17
+ interface TouchableOpacityProps {
18
+ className?: string;
19
+ }
20
+ interface ScrollViewProps {
21
+ className?: string;
22
+ }
23
+ }