vibefast-cli 0.6.0 → 0.6.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibefast-cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "CLI for installing VibeFast features into your monorepo",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,444 @@
1
+ import { MaterialIcons } from '@expo/vector-icons';
2
+ import { ScrollView, StyleSheet, Text, View } from 'react-native';
3
+ import { SafeAreaView } from 'react-native-safe-area-context';
4
+
5
+ import { useThemeConfig } from '../../../lib/use-theme-config';
6
+ import { Timeline } from './timeline-view';
7
+ import type { TimelineItem } from './types';
8
+
9
+ const ShippingDetailsComponent = () => {
10
+ const { colors } = useThemeConfig();
11
+ const styles = createDemoStyles(colors);
12
+ return (
13
+ <View style={styles.detailsCard}>
14
+ <Text style={styles.detailsTitle}>📦 Shipping Information</Text>
15
+ <View style={styles.detailsRow}>
16
+ <Text style={styles.detailsLabel}>Carrier</Text>
17
+ <Text style={styles.detailsValue}>FedEx Express</Text>
18
+ </View>
19
+ <View style={styles.detailsRow}>
20
+ <Text style={styles.detailsLabel}>Tracking ID</Text>
21
+ <Text style={styles.detailsValue}>1Z999AA1234567890</Text>
22
+ </View>
23
+ <View style={styles.detailsRow}>
24
+ <Text style={styles.detailsLabel}>Est. Delivery</Text>
25
+ <Text style={styles.detailsValue}>May 10, 6:00 PM</Text>
26
+ </View>
27
+ </View>
28
+ );
29
+ };
30
+
31
+ const ProjectMilestoneComponent = () => {
32
+ const { colors } = useThemeConfig();
33
+ const styles = createDemoStyles(colors);
34
+ return (
35
+ <View style={styles.detailsCard}>
36
+ <Text style={styles.detailsTitle}>🎯 Milestone Details</Text>
37
+ <View style={styles.detailsRow}>
38
+ <Text style={styles.detailsLabel}>Deliverables</Text>
39
+ <Text style={styles.detailsValue}>Design v2</Text>
40
+ </View>
41
+ <View style={styles.detailsRow}>
42
+ <Text style={styles.detailsLabel}>Team Size</Text>
43
+ <Text style={styles.detailsValue}>5 Designers</Text>
44
+ </View>
45
+ <View style={styles.detailsRow}>
46
+ <Text style={styles.detailsLabel}>Budget</Text>
47
+ <Text style={styles.detailsValue}>$24,500</Text>
48
+ </View>
49
+ </View>
50
+ );
51
+ };
52
+
53
+ const DevelopmentStatusComponent = () => {
54
+ const { colors } = useThemeConfig();
55
+ const styles = createDemoStyles(colors);
56
+ return (
57
+ <View style={styles.detailsCard}>
58
+ <Text style={styles.detailsTitle}>⚡ Development Progress</Text>
59
+ <View style={styles.progressRow}>
60
+ <Text style={styles.progressLabel}>Frontend</Text>
61
+ <View style={styles.progressBar}>
62
+ <View style={[styles.progressFill, { width: '85%' }]} />
63
+ </View>
64
+ <Text style={styles.progressValue}>85%</Text>
65
+ </View>
66
+ <View style={styles.progressRow}>
67
+ <Text style={styles.progressLabel}>Backend</Text>
68
+ <View style={styles.progressBar}>
69
+ <View
70
+ style={[
71
+ styles.progressFill,
72
+ { width: '92%', backgroundColor: colors.success },
73
+ ]}
74
+ />
75
+ </View>
76
+ <Text style={styles.progressValue}>92%</Text>
77
+ </View>
78
+ </View>
79
+ );
80
+ };
81
+
82
+ const TimelineDemo = () => {
83
+ const { colors } = useThemeConfig();
84
+ const styles = createDemoStyles(colors);
85
+
86
+ const orderTimelineItems: TimelineItem[] = [
87
+ {
88
+ id: 1,
89
+ title: 'Order Placed',
90
+ description: "We've received your order and will begin processing it.",
91
+ timestamp: 'May 7, 10:23 AM',
92
+ icon: 'shopping-bag',
93
+ status: 'complete',
94
+ meta: 'Order #38492',
95
+ },
96
+ {
97
+ id: 2,
98
+ title: 'Order Confirmed',
99
+ description: 'Your order is confirmed and ready to ship.',
100
+ timestamp: 'May 7, 11:05 AM',
101
+ icon: 'check-circle',
102
+ status: 'complete',
103
+ meta: 'Ready for shipment',
104
+ },
105
+ {
106
+ id: 3,
107
+ title: 'Shipped',
108
+ description: 'The package has left our facility and is on its way.',
109
+ timestamp: 'May 8, 9:15 AM',
110
+ icon: 'package',
111
+ status: 'complete',
112
+ children: <ShippingDetailsComponent />,
113
+ childrenContainer: { marginTop: 0 },
114
+ meta: 'In Transit',
115
+ },
116
+ {
117
+ id: 4,
118
+ title: 'Delivered',
119
+ timestamp: 'Est. May 10, by 6:00 PM',
120
+ icon: 'home',
121
+ status: 'upcoming',
122
+ meta: 'Pending delivery',
123
+ description: 'Your order will be delivered to your doorstep.',
124
+ },
125
+ ];
126
+
127
+ const projectTimelineItems: TimelineItem[] = [
128
+ {
129
+ id: 1,
130
+ title: 'Project Kickoff',
131
+ description: 'Initial meeting with stakeholders and team formation.',
132
+ timestamp: 'Jan 15, 2024',
133
+ icon: 'play-circle',
134
+ status: 'complete',
135
+ meta: 'Team assembled',
136
+ },
137
+ {
138
+ id: 2,
139
+ title: 'Design Phase',
140
+ description: 'UI/UX design, prototyping, and design system creation.',
141
+ timestamp: 'Feb 12, 2024',
142
+ icon: 'edit-3',
143
+ status: 'complete',
144
+ children: <ProjectMilestoneComponent />,
145
+ childrenContainer: { marginTop: 0 },
146
+ meta: 'Design system v2.0',
147
+ },
148
+ {
149
+ id: 3,
150
+ title: 'Development Sprint',
151
+ description: 'Frontend and backend development in parallel tracks.',
152
+ timestamp: 'Mar 5, 2024',
153
+ icon: 'code',
154
+ status: 'current',
155
+ children: <DevelopmentStatusComponent />,
156
+ childrenContainer: { marginTop: 0 },
157
+ meta: 'In Progress',
158
+ },
159
+ {
160
+ id: 4,
161
+ title: 'Launch',
162
+ description: 'Production deployment and go-live celebration.',
163
+ timestamp: 'Apr 15, 2024',
164
+ icon: 'zap',
165
+ status: 'upcoming',
166
+ meta: 'Launch day',
167
+ },
168
+ ];
169
+
170
+ const userJourneyItems: TimelineItem[] = [
171
+ {
172
+ id: 1,
173
+ title: 'Account Created',
174
+ description: 'User registered with email verification.',
175
+ timestamp: '2 hours ago',
176
+ icon: 'user-plus',
177
+ status: 'complete',
178
+ meta: 'sarah.johnson@email.com',
179
+ },
180
+ {
181
+ id: 2,
182
+ title: 'First Purchase',
183
+ description: 'Completed their first transaction successfully.',
184
+ timestamp: '45 minutes ago',
185
+ icon: 'shopping-cart',
186
+ status: 'complete',
187
+ meta: '$127.50',
188
+ },
189
+ {
190
+ id: 3,
191
+ title: 'App Downloaded',
192
+ description: 'Downloaded and logged into mobile application.',
193
+ timestamp: '12 minutes ago',
194
+ icon: 'smartphone',
195
+ status: 'current',
196
+ meta: 'iOS App',
197
+ },
198
+ ];
199
+
200
+ const handleItemPress = (item: TimelineItem) => {
201
+ console.log('Timeline item pressed:', item.title);
202
+ };
203
+
204
+ return (
205
+ <SafeAreaView style={styles.container}>
206
+ <ScrollView
207
+ contentContainerStyle={styles.content}
208
+ showsVerticalScrollIndicator={false}
209
+ contentInsetAdjustmentBehavior="always"
210
+ scrollEnabled
211
+ >
212
+ <View style={styles.header}>
213
+ <View style={styles.iconContainer}>
214
+ <MaterialIcons name="timeline" size={32} color={colors.primary} />
215
+ </View>
216
+ <Text style={styles.headerTitle}>Timeline Component Demo</Text>
217
+ <Text style={styles.subtitle}>
218
+ Beautiful timelines with various styles and interactive features
219
+ </Text>
220
+ </View>
221
+ <View style={styles.section}>
222
+ <View style={styles.sectionHeader}>
223
+ <Text style={styles.sectionTitle}>🧾 Order Timeline</Text>
224
+ <Text style={styles.sectionSubtitle}>
225
+ Follow your delivery journey
226
+ </Text>
227
+ </View>
228
+
229
+ <View style={styles.timelineWrapper}>
230
+ <Timeline
231
+ metaContainerStyle={styles.metaContainer}
232
+ animationType="rotate"
233
+ items={orderTimelineItems}
234
+ onItemPress={handleItemPress}
235
+ activeColor={colors.primary}
236
+ animated
237
+ titleStyle={styles.timelineTitle}
238
+ descriptionStyle={styles.timelineDescription}
239
+ timestampStyle={styles.timelineTimestamp}
240
+ metaTextStyle={styles.timelineMeta}
241
+ />
242
+ </View>
243
+ </View>
244
+
245
+ <View style={styles.section}>
246
+ <View style={styles.sectionHeader}>
247
+ <Text style={styles.sectionTitle}>🚀 Project Timeline</Text>
248
+ <Text style={styles.sectionSubtitle}>
249
+ Development milestones and progress
250
+ </Text>
251
+ </View>
252
+
253
+ <View style={styles.timelineWrapper}>
254
+ <Timeline
255
+ metaContainerStyle={[
256
+ styles.metaContainer,
257
+ { backgroundColor: colors.card },
258
+ ]}
259
+ animationType="fade"
260
+ items={projectTimelineItems}
261
+ onItemPress={handleItemPress}
262
+ activeColor={colors.success}
263
+ animated
264
+ titleStyle={styles.timelineTitle}
265
+ descriptionStyle={styles.timelineDescription}
266
+ timestampStyle={styles.timelineTimestamp}
267
+ metaTextStyle={styles.timelineMeta}
268
+ />
269
+ </View>
270
+ </View>
271
+
272
+ <View style={styles.section}>
273
+ <View style={styles.sectionHeader}>
274
+ <Text style={styles.sectionTitle}>👤 User Journey</Text>
275
+ <Text style={styles.sectionSubtitle}>
276
+ Real-time user activity tracking
277
+ </Text>
278
+ </View>
279
+
280
+ <View style={styles.timelineWrapper}>
281
+ <Timeline
282
+ metaContainerStyle={[
283
+ styles.metaContainer,
284
+ { backgroundColor: colors.background },
285
+ ]}
286
+ animationType="scale"
287
+ items={userJourneyItems}
288
+ onItemPress={handleItemPress}
289
+ activeColor={colors.destructive}
290
+ animated
291
+ titleStyle={styles.timelineTitle}
292
+ descriptionStyle={styles.timelineDescription}
293
+ timestampStyle={styles.timelineTimestamp}
294
+ metaTextStyle={styles.timelineMeta}
295
+ />
296
+ </View>
297
+ </View>
298
+ </ScrollView>
299
+ </SafeAreaView>
300
+ );
301
+ };
302
+
303
+ const createDemoStyles = (colors: any) =>
304
+ StyleSheet.create({
305
+ container: {
306
+ flex: 1,
307
+ backgroundColor: colors.background,
308
+ },
309
+ content: {
310
+ padding: 24,
311
+ paddingBottom: 48,
312
+ },
313
+ header: {
314
+ alignItems: 'center',
315
+ marginBottom: 32,
316
+ paddingTop: 20,
317
+ },
318
+ iconContainer: {
319
+ width: 64,
320
+ height: 64,
321
+ borderRadius: 32,
322
+ backgroundColor: colors.card,
323
+ alignItems: 'center',
324
+ justifyContent: 'center',
325
+ marginBottom: 16,
326
+ borderWidth: 1,
327
+ borderColor: colors.border,
328
+ },
329
+ headerTitle: {
330
+ fontSize: 28,
331
+ fontWeight: '700',
332
+ color: colors.foreground,
333
+ textAlign: 'center',
334
+ marginBottom: 8,
335
+ },
336
+ subtitle: {
337
+ fontSize: 16,
338
+ color: colors.mutedForeground,
339
+ textAlign: 'center',
340
+ lineHeight: 24,
341
+ maxWidth: 320,
342
+ },
343
+ section: {
344
+ marginBottom: 32,
345
+ },
346
+ sectionTitle: {
347
+ fontSize: 18,
348
+ fontWeight: '600',
349
+ color: colors.foreground,
350
+ marginBottom: 16,
351
+ marginLeft: 4,
352
+ },
353
+ sectionHeader: {
354
+ marginBottom: 16,
355
+ },
356
+ sectionSubtitle: {
357
+ fontSize: 14,
358
+ color: colors.mutedForeground,
359
+ marginTop: 4,
360
+ marginLeft: 4,
361
+ },
362
+ timelineWrapper: {
363
+ backgroundColor: colors.card,
364
+ borderWidth: 1,
365
+ borderColor: colors.border,
366
+ borderRadius: 12,
367
+ padding: 16,
368
+ },
369
+ metaContainer: {
370
+ backgroundColor: colors.background,
371
+ borderRadius: 8,
372
+ padding: 8,
373
+ },
374
+ timelineTitle: {
375
+ color: colors.foreground,
376
+ fontWeight: '600',
377
+ },
378
+ timelineDescription: {
379
+ color: colors.mutedForeground,
380
+ },
381
+ timelineTimestamp: {
382
+ color: colors.mutedForeground,
383
+ },
384
+ timelineMeta: {
385
+ color: colors.foreground,
386
+ },
387
+ detailsCard: {
388
+ backgroundColor: colors.background,
389
+ borderRadius: 12,
390
+ padding: 12,
391
+ marginTop: 8,
392
+ },
393
+ detailsTitle: {
394
+ fontSize: 14,
395
+ color: colors.foreground,
396
+ fontWeight: '500',
397
+ marginBottom: 8,
398
+ },
399
+ detailsRow: {
400
+ flexDirection: 'row',
401
+ justifyContent: 'space-between',
402
+ marginBottom: 6,
403
+ },
404
+ detailsLabel: {
405
+ fontSize: 13,
406
+ color: colors.mutedForeground,
407
+ },
408
+ detailsValue: {
409
+ fontSize: 13,
410
+ color: colors.foreground,
411
+ fontWeight: '500',
412
+ },
413
+ progressRow: {
414
+ flexDirection: 'row',
415
+ alignItems: 'center',
416
+ marginBottom: 8,
417
+ },
418
+ progressLabel: {
419
+ fontSize: 12,
420
+ color: colors.mutedForeground,
421
+ width: 60,
422
+ },
423
+ progressBar: {
424
+ flex: 1,
425
+ height: 6,
426
+ backgroundColor: colors.border,
427
+ borderRadius: 3,
428
+ marginHorizontal: 12,
429
+ },
430
+ progressFill: {
431
+ height: 6,
432
+ backgroundColor: colors.primary,
433
+ borderRadius: 3,
434
+ },
435
+ progressValue: {
436
+ fontSize: 12,
437
+ color: colors.foreground,
438
+ fontWeight: '500',
439
+ width: 35,
440
+ textAlign: 'right',
441
+ },
442
+ });
443
+
444
+ export default TimelineDemo;
@@ -0,0 +1,355 @@
1
+ /* eslint-disable */
2
+
3
+ import { Feather } from '@expo/vector-icons';
4
+ import React, { useEffect } from 'react';
5
+ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
6
+ import Animated, {
7
+ FadeInDown,
8
+ interpolateColor,
9
+ LinearTransition,
10
+ useAnimatedStyle,
11
+ useSharedValue,
12
+ withSequence,
13
+ withSpring,
14
+ withTiming,
15
+ } from 'react-native-reanimated';
16
+
17
+ import { useThemeConfig } from '../../../lib/use-theme-config';
18
+ import type { TimelineProps } from './types';
19
+
20
+ const AnimatedTouchableOpacity =
21
+ Animated.createAnimatedComponent(TouchableOpacity);
22
+ const AnimatedFeather = Animated.createAnimatedComponent(Feather);
23
+
24
+ export const Timeline: React.FC<TimelineProps> &
25
+ React.FunctionComponent<TimelineProps> = ({
26
+ items = [],
27
+ activeColor: propsActiveColor,
28
+ inactiveColor: propsInactiveColor,
29
+ animated = true,
30
+ animationType = 'bounce',
31
+ onItemPress,
32
+ containerStyle,
33
+ titleStyle,
34
+ descriptionStyle,
35
+ timestampStyle,
36
+ lineWidth = 2,
37
+ iconSize = 20,
38
+ metaContainerStyle,
39
+ metaTextStyle,
40
+ }: TimelineProps): React.ReactNode & React.JSX.Element => {
41
+ const { colors } = useThemeConfig();
42
+ const activeColor = propsActiveColor ?? colors.primary;
43
+ const inactiveColor = propsInactiveColor ?? colors.muted;
44
+
45
+ const statusRefs = React.useRef<Record<string | number, string>>({});
46
+
47
+ useEffect(() => {
48
+ items.forEach((item) => {
49
+ statusRefs.current[item.id] = item.status || 'upcoming';
50
+ });
51
+
52
+ return () => {
53
+ statusRefs.current = {};
54
+ };
55
+ }, [items]);
56
+
57
+ if (!items || items.length === 0) {
58
+ return null as unknown as React.ReactNode & React.JSX.Element;
59
+ }
60
+
61
+ return (
62
+ <Animated.View style={[styles.container, containerStyle]}>
63
+ {items.map((item, index) => {
64
+ const isFirst = index === 0;
65
+ const isLast = index === items.length - 1;
66
+ const isComplete = item.status === 'complete';
67
+ const isCurrent = item.status === 'current';
68
+ const isUpcoming = item.status === 'upcoming' || !item.status;
69
+
70
+ const prevStatus = statusRefs.current[item.id];
71
+ const wasComplete = prevStatus === 'complete';
72
+ const statusChanged = prevStatus && prevStatus !== item.status;
73
+ statusRefs.current[item.id] = item.status || 'upcoming';
74
+
75
+ const dotScale = useSharedValue(statusChanged ? 1.5 : 1);
76
+ const dotColorAnimated = useSharedValue(
77
+ isComplete ? 1 : isCurrent ? 0.5 : 0,
78
+ );
79
+ const lineProgress = useSharedValue(isComplete ? 1 : 0);
80
+ const iconRotate = useSharedValue(statusChanged ? 0 : 1);
81
+
82
+ useEffect(() => {
83
+ if (statusChanged) {
84
+ switch (animationType) {
85
+ case 'bounce':
86
+ dotScale.value = withSequence(
87
+ withTiming(1.5, { duration: 200 }),
88
+ withSpring(1),
89
+ );
90
+ break;
91
+ case 'spring':
92
+ dotScale.value = withSpring(1.2, { damping: 2, stiffness: 80 });
93
+ break;
94
+ case 'rotate':
95
+ iconRotate.value = withSequence(
96
+ withTiming(0, { duration: 10 }),
97
+ withTiming(4, { duration: 800 }),
98
+ );
99
+ dotScale.value = withSequence(
100
+ withTiming(1.6, { duration: 200 }),
101
+ withSpring(1),
102
+ );
103
+ dotColorAnimated.value = withSequence(
104
+ withTiming(0, { duration: 200 }),
105
+ withTiming(isComplete ? 1 : isCurrent ? 0.5 : 0, {
106
+ duration: 400,
107
+ }),
108
+ );
109
+ break;
110
+ case 'fade':
111
+ dotColorAnimated.value = withSequence(
112
+ withTiming(0, { duration: 200 }),
113
+ withTiming(isComplete ? 1 : isCurrent ? 0.5 : 0, {
114
+ duration: 400,
115
+ }),
116
+ );
117
+ break;
118
+ case 'scale':
119
+ dotScale.value = withSequence(
120
+ withTiming(0.5, { duration: 200 }),
121
+ withTiming(1.2, { duration: 200 }),
122
+ withTiming(1, { duration: 200 }),
123
+ );
124
+ break;
125
+ default:
126
+ dotScale.value = withSequence(
127
+ withTiming(1.5, { duration: 200 }),
128
+ withSpring(1),
129
+ );
130
+ }
131
+
132
+ dotColorAnimated.value = withTiming(
133
+ isComplete ? 1 : isCurrent ? 0.5 : 0,
134
+ { duration: 400 },
135
+ );
136
+
137
+ iconRotate.value = withSequence(
138
+ withTiming(0, { duration: 10 }),
139
+ withTiming(1, { duration: 400 }),
140
+ );
141
+
142
+ if (isComplete) {
143
+ lineProgress.value = withTiming(1, { duration: 600 });
144
+ } else if (wasComplete) {
145
+ lineProgress.value = withTiming(0, { duration: 600 });
146
+ }
147
+ } else {
148
+ lineProgress.value = isComplete ? 1 : 0;
149
+ }
150
+ }, [
151
+ item.status,
152
+ isComplete,
153
+ isCurrent,
154
+ animationType,
155
+ dotColorAnimated,
156
+ dotScale,
157
+ iconRotate,
158
+ lineProgress,
159
+ statusChanged,
160
+ wasComplete,
161
+ ]);
162
+
163
+ const dotAnimatedStyle = useAnimatedStyle(() => {
164
+ return {
165
+ transform: [{ scale: dotScale.value }],
166
+ backgroundColor: interpolateColor(
167
+ dotColorAnimated.value,
168
+ [0, 0.5, 1],
169
+ [inactiveColor, activeColor, activeColor],
170
+ ),
171
+ };
172
+ });
173
+
174
+ const lineAnimatedStyle = useAnimatedStyle(() => {
175
+ return {
176
+ backgroundColor: interpolateColor(
177
+ lineProgress.value,
178
+ [0, 1],
179
+ [inactiveColor, activeColor],
180
+ ),
181
+ width: lineWidth,
182
+ transform: [{ scaleY: lineProgress.value }],
183
+ opacity: 0.6 + lineProgress.value * 0.4,
184
+ };
185
+ });
186
+
187
+ const iconAnimatedStyle = useAnimatedStyle(() => {
188
+ return {
189
+ transform: [{ rotate: `${iconRotate.value * 360}deg` }],
190
+ opacity: 0.8 + iconRotate.value * 0.2,
191
+ };
192
+ });
193
+
194
+ const iconName =
195
+ item.icon ||
196
+ (isComplete ? 'check' : isCurrent ? 'activity' : 'circle');
197
+
198
+ const textColor =
199
+ isComplete || isCurrent ? colors.foreground : colors.mutedForeground;
200
+
201
+ return (
202
+ <AnimatedTouchableOpacity
203
+ key={item.id}
204
+ style={styles.itemContainer}
205
+ activeOpacity={onItemPress ? 0.7 : 1}
206
+ onPress={() => onItemPress && onItemPress(item)}
207
+ entering={
208
+ animated ? FadeInDown.delay(index * 100).springify() : undefined
209
+ }
210
+ layout={LinearTransition.springify()}
211
+ >
212
+ <View style={styles.timelineColumn}>
213
+ <Animated.View style={[styles.dot, dotAnimatedStyle]}>
214
+ <Animated.View style={[{}, iconAnimatedStyle]}>
215
+ <AnimatedFeather
216
+ name={iconName as any}
217
+ size={iconSize * 0.7}
218
+ color={colors.primaryForeground}
219
+ />
220
+ </Animated.View>
221
+ </Animated.View>
222
+
223
+ {!isLast && (
224
+ <Animated.View style={[styles.line, lineAnimatedStyle]} />
225
+ )}
226
+ </View>
227
+
228
+ <View style={styles.contentColumn}>
229
+ <View style={styles.itemHeader}>
230
+ <Text style={[styles.title, { color: textColor }, titleStyle]}>
231
+ {item.title}
232
+ </Text>
233
+
234
+ {item.timestamp && (
235
+ <Text
236
+ style={[
237
+ styles.timestamp,
238
+ { color: colors.mutedForeground },
239
+ timestampStyle,
240
+ ]}
241
+ >
242
+ {item.timestamp}
243
+ </Text>
244
+ )}
245
+ </View>
246
+
247
+ {item.description && (
248
+ <Text
249
+ style={[
250
+ styles.description,
251
+ { color: colors.mutedForeground },
252
+ descriptionStyle,
253
+ ]}
254
+ >
255
+ {item.description}
256
+ </Text>
257
+ )}
258
+
259
+ {item.meta && (
260
+ <View style={[styles.metaContainer, metaContainerStyle]}>
261
+ <Text
262
+ style={[
263
+ styles.metaText,
264
+ { color: colors.mutedForeground },
265
+ metaTextStyle,
266
+ ]}
267
+ >
268
+ {item.meta}
269
+ </Text>
270
+ </View>
271
+ )}
272
+
273
+ {item.children && (
274
+ <View
275
+ style={[styles.childrenContainer, item.childrenContainer]}
276
+ >
277
+ {item.children}
278
+ </View>
279
+ )}
280
+ </View>
281
+ </AnimatedTouchableOpacity>
282
+ );
283
+ })}
284
+ </Animated.View>
285
+ );
286
+ };
287
+
288
+ const styles = StyleSheet.create({
289
+ container: {
290
+ padding: 16,
291
+ },
292
+ itemContainer: {
293
+ flexDirection: 'row',
294
+ marginBottom: 24,
295
+ },
296
+ timelineColumn: {
297
+ alignItems: 'center',
298
+ width: 40,
299
+ },
300
+ contentColumn: {
301
+ flex: 1,
302
+ marginLeft: 12,
303
+ marginTop: -4,
304
+ },
305
+ dot: {
306
+ width: 28,
307
+ height: 28,
308
+ borderRadius: 14,
309
+ justifyContent: 'center',
310
+ alignItems: 'center',
311
+ elevation: 2,
312
+ shadowColor: '#000',
313
+ shadowOffset: { width: 0, height: 1 },
314
+ shadowOpacity: 0.1,
315
+ shadowRadius: 1,
316
+ },
317
+ line: {
318
+ flex: 1,
319
+ marginTop: 4,
320
+ },
321
+ itemHeader: {
322
+ flexDirection: 'row',
323
+ justifyContent: 'space-between',
324
+ alignItems: 'flex-start',
325
+ marginBottom: 6,
326
+ },
327
+ title: {
328
+ fontSize: 16,
329
+ fontWeight: '600',
330
+ flex: 1,
331
+ },
332
+ description: {
333
+ fontSize: 14,
334
+ lineHeight: 20,
335
+ marginBottom: 8,
336
+ },
337
+ timestamp: {
338
+ fontSize: 12,
339
+ marginLeft: 8,
340
+ },
341
+ metaContainer: {
342
+ paddingHorizontal: 10,
343
+ paddingVertical: 6,
344
+ borderRadius: 6,
345
+ alignSelf: 'flex-start',
346
+ marginTop: 4,
347
+ marginBottom: 8,
348
+ },
349
+ metaText: {
350
+ fontSize: 12,
351
+ },
352
+ childrenContainer: {
353
+ padding: 12,
354
+ },
355
+ });
@@ -0,0 +1,31 @@
1
+ import type { Feather } from '@expo/vector-icons';
2
+ import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
3
+
4
+ export interface TimelineItem {
5
+ id: string | number;
6
+ title: string;
7
+ description?: string;
8
+ timestamp?: string;
9
+ icon?: keyof typeof Feather.glyphMap;
10
+ status?: 'complete' | 'current' | 'upcoming';
11
+ meta?: string;
12
+ children?: React.ReactNode;
13
+ childrenContainer?: StyleProp<ViewStyle>;
14
+ }
15
+
16
+ export interface TimelineProps {
17
+ items: TimelineItem[];
18
+ activeColor?: string;
19
+ inactiveColor?: string;
20
+ animated?: boolean;
21
+ animationType?: 'bounce' | 'spring' | 'rotate' | 'fade' | 'scale';
22
+ onItemPress?: (item: TimelineItem) => void;
23
+ containerStyle?: ViewStyle;
24
+ metaContainerStyle?: StyleProp<ViewStyle>;
25
+ titleStyle?: TextStyle;
26
+ descriptionStyle?: TextStyle;
27
+ timestampStyle?: TextStyle;
28
+ lineWidth?: number;
29
+ iconSize?: number;
30
+ metaTextStyle?: StyleProp<TextStyle>;
31
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "0",
3
+ "version": "1.0.0",
4
+ "description": "Advanced UI component: 0",
5
+ "target": "native",
6
+ "copy": [
7
+ {
8
+ "from": "apps/native/src/components/advanced-ui/timeline",
9
+ "to": "apps/native/src/components/advanced-ui/timeline"
10
+ }
11
+ ],
12
+ "dependencies": {
13
+ "expo": [
14
+ "react-native-reanimated",
15
+ "react-native-gesture-handler"
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,366 @@
1
+ import { Text, View } from 'react-native';
2
+ import AnimatedGlow, { type PresetConfig } from 'react-native-animated-glow';
3
+
4
+ import { useThemeConfig } from '@/lib/use-theme-config';
5
+
6
+ export type Preset = (typeof presets)[keyof typeof presets];
7
+
8
+ export const presets = {
9
+ cosmicNebula: {
10
+ cornerRadius: 70,
11
+ outlineWidth: 3,
12
+ borderColor: [
13
+ 'rgba(255, 171, 203, 1)',
14
+ 'rgba(112, 49, 164, 1)',
15
+ 'rgba(35, 21, 50, 1)',
16
+ ],
17
+ backgroundColor: '#222',
18
+ animationSpeed: 2,
19
+ randomness: 0.01,
20
+ borderSpeedMultiplier: 1,
21
+ glowLayers: [
22
+ {
23
+ glowPlacement: 'behind',
24
+ colors: ['#483D8B', '#8A2BE2', '#9370DB'],
25
+ glowSize: 20,
26
+ opacity: 0.1,
27
+ speedMultiplier: 1,
28
+ coverage: 1,
29
+ relativeOffset: 0,
30
+ },
31
+ {
32
+ glowPlacement: 'behind',
33
+ colors: [
34
+ 'rgba(185, 185, 250, 1)',
35
+ 'rgba(199, 129, 199, 1)',
36
+ 'rgba(77, 61, 175, 1)',
37
+ ],
38
+ glowSize: [2, 6],
39
+ opacity: 0.6,
40
+ speedMultiplier: 1,
41
+ coverage: 1,
42
+ relativeOffset: 0,
43
+ },
44
+ {
45
+ glowPlacement: 'over',
46
+ colors: ['rgba(185, 185, 250, 1)', 'rgba(225, 133, 242, 1)'],
47
+ glowSize: [0, 12],
48
+ opacity: 0.05,
49
+ speedMultiplier: 1.2,
50
+ coverage: 0.5,
51
+ relativeOffset: 0,
52
+ },
53
+ {
54
+ glowPlacement: 'over',
55
+ colors: ['rgba(185, 185, 250, 1)', 'rgba(255, 140, 255, 1)'],
56
+ glowSize: [0, 1],
57
+ opacity: 1,
58
+ speedMultiplier: 1.2,
59
+ coverage: 0.3,
60
+ relativeOffset: 0.9,
61
+ },
62
+ ],
63
+ },
64
+ oceanSunset: {
65
+ cornerRadius: 70,
66
+ outlineWidth: 4,
67
+ borderColor: [
68
+ 'rgba(255, 124, 171, 1)',
69
+ 'rgba(63, 100, 199, 1)',
70
+ 'rgba(240, 115, 46, 1)',
71
+ ],
72
+ backgroundColor: 'rgba(21, 21, 21, 1)',
73
+ animationSpeed: 2,
74
+ randomness: 0.01,
75
+ borderSpeedMultiplier: 1,
76
+ glowLayers: [
77
+ {
78
+ glowPlacement: 'behind',
79
+ colors: ['#f82fc6', '#5a4ff9', '#ff923e'],
80
+ glowSize: 15,
81
+ opacity: 0.1,
82
+ speedMultiplier: 1,
83
+ coverage: 1,
84
+ relativeOffset: 0,
85
+ },
86
+ {
87
+ glowPlacement: 'behind',
88
+ colors: [
89
+ 'rgba(255, 89, 213, 1)',
90
+ 'rgba(63, 89, 255, 1)',
91
+ 'rgba(255, 164, 0, 1)',
92
+ ],
93
+ glowSize: 5,
94
+ opacity: 0.5,
95
+ speedMultiplier: 1,
96
+ coverage: 1,
97
+ relativeOffset: 0,
98
+ },
99
+ ],
100
+ },
101
+ glowingBorder: {
102
+ cornerRadius: 70,
103
+ outlineWidth: 1,
104
+ borderColor: [
105
+ 'rgba(16, 16, 16, 1)',
106
+ 'rgba(227, 74, 255, 0.3)',
107
+ 'rgba(142, 88, 163, 1)',
108
+ 'rgba(98, 181, 255, 1)',
109
+ 'rgba(199, 208, 255, 1)',
110
+ 'rgba(55, 112, 169, 1)',
111
+ ],
112
+ backgroundColor: 'rgba(0, 0, 0, 1)',
113
+ animationSpeed: 1,
114
+ randomness: 0.01,
115
+ borderSpeedMultiplier: 1,
116
+ glowLayers: [
117
+ {
118
+ glowPlacement: 'over',
119
+ colors: [
120
+ 'rgba(0, 0, 0, 0)',
121
+ 'rgba(137, 73, 151, 1)',
122
+ 'rgba(85, 68, 216, 1)',
123
+ ],
124
+ glowSize: [0, 25, 20, 0],
125
+ opacity: 0.15,
126
+ speedMultiplier: 1,
127
+ coverage: 1,
128
+ relativeOffset: 0,
129
+ },
130
+ {
131
+ glowPlacement: 'over',
132
+ colors: [
133
+ 'rgba(0, 0, 0, 0)',
134
+ 'rgba(137, 73, 151, 1)',
135
+ 'rgba(85, 68, 216, 1)',
136
+ ],
137
+ glowSize: [0, 5, 5, 0],
138
+ opacity: 0.2,
139
+ speedMultiplier: 1,
140
+ coverage: 1,
141
+ relativeOffset: 0,
142
+ },
143
+ {
144
+ glowPlacement: 'over',
145
+ colors: ['rgba(166, 68, 195, 1)', 'rgba(245, 219, 255, 1)'],
146
+ glowSize: [1, 8],
147
+ opacity: 0.06,
148
+ speedMultiplier: 1,
149
+ coverage: 0.25,
150
+ relativeOffset: 0.85,
151
+ },
152
+ {
153
+ glowPlacement: 'over',
154
+ colors: ['rgba(225, 102, 235, 1)', 'rgba(245, 219, 255, 1)'],
155
+ glowSize: [0, 0.3],
156
+ opacity: 1,
157
+ speedMultiplier: 1,
158
+ coverage: 0.25,
159
+ relativeOffset: 0.85,
160
+ },
161
+ {
162
+ glowPlacement: 'over',
163
+ colors: ['rgba(83, 172, 255, 1)', 'rgba(0, 181, 255, 1)'],
164
+ glowSize: [0, 8],
165
+ opacity: 0.1,
166
+ speedMultiplier: 1,
167
+ coverage: 0.3,
168
+ relativeOffset: 0.4,
169
+ },
170
+ {
171
+ glowPlacement: 'over',
172
+ colors: ['rgba(83, 172, 255, 1)', 'rgba(255, 255, 255, 1)'],
173
+ glowSize: [0, 0.3],
174
+ opacity: 1,
175
+ speedMultiplier: 1,
176
+ coverage: 0.25,
177
+ relativeOffset: 0.4,
178
+ },
179
+ ],
180
+ },
181
+ cyberPink: {
182
+ cornerRadius: 70,
183
+ outlineWidth: 8,
184
+ borderColor: ['rgba(177, 102, 255, 1)', 'rgba(255, 102, 163, 1)'],
185
+ backgroundColor: 'rgba(27, 0, 25, 1)',
186
+ animationSpeed: 3,
187
+ randomness: 0.01,
188
+ borderSpeedMultiplier: 1,
189
+ glowLayers: [
190
+ {
191
+ glowPlacement: 'behind',
192
+ colors: ['#FF1493', 'rgba(206, 0, 255, 1)', '#DB7093'],
193
+ glowSize: 30,
194
+ opacity: 0.2,
195
+ speedMultiplier: 1,
196
+ coverage: 1,
197
+ relativeOffset: 0,
198
+ },
199
+ {
200
+ glowPlacement: 'behind',
201
+ colors: ['rgba(254, 160, 177, 1)', 'rgba(206, 180, 255, 1)'],
202
+ glowSize: 12,
203
+ opacity: 0.2,
204
+ speedMultiplier: 1,
205
+ coverage: 1,
206
+ relativeOffset: 0,
207
+ },
208
+ {
209
+ glowPlacement: 'behind',
210
+ colors: ['rgba(255, 164, 180, 1)', 'rgba(255, 217, 217, 1)'],
211
+ glowSize: 4,
212
+ opacity: 1,
213
+ speedMultiplier: 1,
214
+ coverage: 1,
215
+ relativeOffset: 0,
216
+ },
217
+ ],
218
+ },
219
+ defaultRainbow: {
220
+ cornerRadius: 30,
221
+ outlineWidth: 4,
222
+ borderColor: [
223
+ 'rgba(238, 255, 0, 1)',
224
+ 'rgba(79, 255, 0, 1)',
225
+ 'rgba(46, 90, 255, 1)',
226
+ 'rgba(254, 0, 255, 1)',
227
+ 'rgba(231, 23, 23, 1)',
228
+ ],
229
+ backgroundColor: 'rgba(10, 10, 10, 1)',
230
+ animationSpeed: 1.2,
231
+ randomness: 0.01,
232
+ borderSpeedMultiplier: 1,
233
+ glowLayers: [
234
+ {
235
+ glowPlacement: 'behind',
236
+ colors: [
237
+ 'rgba(205, 201, 35, 1)',
238
+ 'rgba(0, 255, 79, 1)',
239
+ 'rgba(0, 119, 255, 1)',
240
+ 'rgba(239, 0, 255, 1)',
241
+ 'rgba(222, 28, 28, 1)',
242
+ ],
243
+ glowSize: 34,
244
+ opacity: 0.2,
245
+ speedMultiplier: 1,
246
+ coverage: 1,
247
+ relativeOffset: 0,
248
+ },
249
+ {
250
+ glowPlacement: 'behind',
251
+ colors: [
252
+ 'rgba(185, 182, 32, 1)',
253
+ 'rgba(0, 255, 79, 1)',
254
+ 'rgba(0, 119, 255, 1)',
255
+ 'rgba(239, 0, 255, 1)',
256
+ 'rgba(222, 28, 28, 1)',
257
+ ],
258
+ glowSize: 6,
259
+ opacity: 0.5,
260
+ speedMultiplier: 1,
261
+ coverage: 1,
262
+ relativeOffset: 0,
263
+ },
264
+ {
265
+ glowPlacement: 'behind',
266
+ colors: ['#FFFFFF'],
267
+ glowSize: [2, 8, 8, 2],
268
+ opacity: 0.2,
269
+ speedMultiplier: 2,
270
+ coverage: 0.5,
271
+ relativeOffset: 0,
272
+ },
273
+ ],
274
+ },
275
+ arcticFreeze: {
276
+ cornerRadius: 60,
277
+ outlineWidth: 4,
278
+ borderColor: 'white',
279
+ backgroundColor: 'rgba(228, 246, 255, 1)',
280
+ animationSpeed: 1,
281
+ randomness: 0.01,
282
+ borderSpeedMultiplier: 1,
283
+ glowLayers: [
284
+ {
285
+ glowPlacement: 'behind',
286
+ colors: ['#00FFFF', '#E0FFFF'],
287
+ glowSize: 10,
288
+ opacity: 0.4,
289
+ speedMultiplier: 1,
290
+ coverage: 1,
291
+ relativeOffset: 0,
292
+ },
293
+ {
294
+ glowPlacement: 'behind',
295
+ colors: ['#FFFFFF', '#AFEEEE'],
296
+ glowSize: 4,
297
+ opacity: 1,
298
+ speedMultiplier: 1,
299
+ coverage: 1,
300
+ relativeOffset: 0,
301
+ },
302
+ ],
303
+ },
304
+ auroraBorealis: {
305
+ cornerRadius: 30,
306
+ outlineWidth: 0,
307
+ borderColor: 'white',
308
+ backgroundColor: '#222',
309
+ animationSpeed: 1,
310
+ randomness: 0.01,
311
+ borderSpeedMultiplier: 1,
312
+ glowLayers: [
313
+ {
314
+ glowPlacement: 'behind',
315
+ colors: ['#4ef96d', '#33a0ff', '#f5519f'],
316
+ glowSize: 30,
317
+ opacity: 0.1,
318
+ speedMultiplier: 1,
319
+ coverage: 1,
320
+ relativeOffset: 0,
321
+ },
322
+ {
323
+ glowPlacement: 'behind',
324
+ colors: ['#4ef96d', 'rgba(116, 159, 255, 1)', 'rgba(255, 114, 170, 1)'],
325
+ glowSize: 10,
326
+ opacity: 0.5,
327
+ speedMultiplier: 0.8,
328
+ coverage: 1,
329
+ relativeOffset: 0,
330
+ },
331
+ {
332
+ glowPlacement: 'behind',
333
+ colors: ['#4ef96d', 'rgba(116, 159, 255, 1)', 'rgba(255, 114, 170, 1)'],
334
+ glowSize: 3,
335
+ opacity: 1,
336
+ speedMultiplier: 0.8,
337
+ coverage: 1,
338
+ relativeOffset: 0,
339
+ },
340
+ ],
341
+ },
342
+ } as const;
343
+
344
+ interface GlowingButtonProps {
345
+ preset: keyof typeof presets; // Only allows valid preset keys
346
+ label: string;
347
+ }
348
+
349
+ export default function GlowingButton({ preset, label }: GlowingButtonProps) {
350
+ const theme = useThemeConfig();
351
+ return (
352
+ <AnimatedGlow preset={presets[preset] as unknown as PresetConfig}>
353
+ <View
354
+ className="rounded-full p-5"
355
+ style={{ backgroundColor: theme.colors.secondary }}
356
+ >
357
+ <Text
358
+ className="text-center text-base font-semibold"
359
+ style={{ color: theme.colors.secondaryForeground }}
360
+ >
361
+ {label}
362
+ </Text>
363
+ </View>
364
+ </AnimatedGlow>
365
+ );
366
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "glowing-button",
3
+ "version": "1.0.0",
4
+ "description": "Animated glowing button with multiple presets",
5
+ "target": "native",
6
+ "copy": [
7
+ {
8
+ "from": "apps/native/src/components/advanced-ui/buttons",
9
+ "to": "apps/native/src/components/advanced-ui/buttons"
10
+ }
11
+ ],
12
+ "dependencies": {
13
+ "expo": [
14
+ "react-native-reanimated"
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+
3
+ # Create advanced UI recipes from monorepo components
4
+
5
+ RECIPES_DIR="recipes"
6
+ MONOREPO="../vibefast-monorepo"
7
+
8
+ # Define advanced UI components
9
+ declare -A COMPONENTS=(
10
+ ["glowing-button"]="buttons"
11
+ ["animated-chip"]="chip"
12
+ ["number-stepper"]="stepper"
13
+ ["animated-switch"]="switch"
14
+ ["progress-circle"]="progress-bars"
15
+ ["swipe-slider"]="sliders"
16
+ ["timeline"]="timeline"
17
+ )
18
+
19
+ for component in "${!COMPONENTS[@]}"; do
20
+ folder="${COMPONENTS[$component]}"
21
+ echo "Creating recipe for $component from $folder..."
22
+
23
+ # Create recipe directory structure
24
+ mkdir -p "$RECIPES_DIR/$component/apps/native/src/components/advanced-ui/$folder"
25
+
26
+ # Copy component files
27
+ cp -r "$MONOREPO/apps/native/src/components/advanced-ui/$folder"/* \
28
+ "$RECIPES_DIR/$component/apps/native/src/components/advanced-ui/$folder/" 2>/dev/null || true
29
+
30
+ # Create recipe.json
31
+ cat > "$RECIPES_DIR/$component/recipe.json" <<EOF
32
+ {
33
+ "name": "$component",
34
+ "version": "1.0.0",
35
+ "description": "Advanced UI component: $component",
36
+ "target": "native",
37
+ "copy": [
38
+ {
39
+ "from": "apps/native/src/components/advanced-ui/$folder",
40
+ "to": "apps/native/src/components/advanced-ui/$folder"
41
+ }
42
+ ],
43
+ "dependencies": {
44
+ "expo": [
45
+ "react-native-reanimated",
46
+ "react-native-gesture-handler"
47
+ ]
48
+ }
49
+ }
50
+ EOF
51
+
52
+ echo "✓ Created $component recipe"
53
+ done
54
+
55
+ echo ""
56
+ echo "All advanced UI recipes created!"
57
+ echo "Now run: ./recipes/upload-all.sh"