vibefast-cli 0.1.1

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 (250) hide show
  1. package/FINAL-STATUS.md +144 -0
  2. package/HOW-IT-WORKS.md +559 -0
  3. package/PLAN.md +453 -0
  4. package/README.md +129 -0
  5. package/RECIPES-READY.md +172 -0
  6. package/STATUS.md +199 -0
  7. package/SUCCESS.md +259 -0
  8. package/TESTING-CHECKLIST.md +450 -0
  9. package/cloudflare-worker/.wrangler/state/v3/kv/64907821e2634080acce34618d2f3d4c/blobs/11f2769953c717e188062bc644da97c1fd1e4d6d0813a226ce7567dba759afab0000019a736fb8d4 +1 -0
  10. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite +0 -0
  11. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-shm +0 -0
  12. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-wal +0 -0
  13. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite +0 -0
  14. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-shm +0 -0
  15. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-wal +0 -0
  16. package/cloudflare-worker/.wrangler/state/v3/r2/vibefast-recipes/blobs/620e8cf7c35d9806da25dee237e1d7e8b2432bd98f755b60e2c7f08a48d2c7b90000019a73736484 +0 -0
  17. package/cloudflare-worker/MIGRATION.md +160 -0
  18. package/cloudflare-worker/QUICKSTART.md +200 -0
  19. package/cloudflare-worker/README.md +242 -0
  20. package/cloudflare-worker/generate-token.js +32 -0
  21. package/cloudflare-worker/mini-native@latest.zip +0 -0
  22. package/cloudflare-worker/setup.sh +143 -0
  23. package/cloudflare-worker/test-recipe/apps/native/src/app/mini/index.tsx +15 -0
  24. package/cloudflare-worker/test-recipe/recipe.json +16 -0
  25. package/cloudflare-worker/worker.js +308 -0
  26. package/cloudflare-worker/wrangler.toml +13 -0
  27. package/dist/commands/add.d.ts +3 -0
  28. package/dist/commands/add.d.ts.map +1 -0
  29. package/dist/commands/add.js +149 -0
  30. package/dist/commands/add.js.map +1 -0
  31. package/dist/commands/devices.d.ts +3 -0
  32. package/dist/commands/devices.d.ts.map +1 -0
  33. package/dist/commands/devices.js +35 -0
  34. package/dist/commands/devices.js.map +1 -0
  35. package/dist/commands/doctor.d.ts +3 -0
  36. package/dist/commands/doctor.d.ts.map +1 -0
  37. package/dist/commands/doctor.js +67 -0
  38. package/dist/commands/doctor.js.map +1 -0
  39. package/dist/commands/list.d.ts +3 -0
  40. package/dist/commands/list.d.ts.map +1 -0
  41. package/dist/commands/list.js +40 -0
  42. package/dist/commands/list.js.map +1 -0
  43. package/dist/commands/login.d.ts +3 -0
  44. package/dist/commands/login.d.ts.map +1 -0
  45. package/dist/commands/login.js +23 -0
  46. package/dist/commands/login.js.map +1 -0
  47. package/dist/commands/logout.d.ts +3 -0
  48. package/dist/commands/logout.d.ts.map +1 -0
  49. package/dist/commands/logout.js +16 -0
  50. package/dist/commands/logout.js.map +1 -0
  51. package/dist/commands/remove.d.ts +3 -0
  52. package/dist/commands/remove.d.ts.map +1 -0
  53. package/dist/commands/remove.js +67 -0
  54. package/dist/commands/remove.js.map +1 -0
  55. package/dist/core/__tests__/journal.test.d.ts +2 -0
  56. package/dist/core/__tests__/journal.test.d.ts.map +1 -0
  57. package/dist/core/__tests__/journal.test.js +101 -0
  58. package/dist/core/__tests__/journal.test.js.map +1 -0
  59. package/dist/core/__tests__/validate.test.d.ts +2 -0
  60. package/dist/core/__tests__/validate.test.d.ts.map +1 -0
  61. package/dist/core/__tests__/validate.test.js +53 -0
  62. package/dist/core/__tests__/validate.test.js.map +1 -0
  63. package/dist/core/archive.d.ts +2 -0
  64. package/dist/core/archive.d.ts.map +1 -0
  65. package/dist/core/archive.js +59 -0
  66. package/dist/core/archive.js.map +1 -0
  67. package/dist/core/auth.d.ts +15 -0
  68. package/dist/core/auth.d.ts.map +1 -0
  69. package/dist/core/auth.js +76 -0
  70. package/dist/core/auth.js.map +1 -0
  71. package/dist/core/codemod.d.ts +20 -0
  72. package/dist/core/codemod.d.ts.map +1 -0
  73. package/dist/core/codemod.js +150 -0
  74. package/dist/core/codemod.js.map +1 -0
  75. package/dist/core/fsx.d.ts +12 -0
  76. package/dist/core/fsx.d.ts.map +1 -0
  77. package/dist/core/fsx.js +70 -0
  78. package/dist/core/fsx.js.map +1 -0
  79. package/dist/core/http.d.ts +30 -0
  80. package/dist/core/http.d.ts.map +1 -0
  81. package/dist/core/http.js +95 -0
  82. package/dist/core/http.js.map +1 -0
  83. package/dist/core/journal.d.ts +18 -0
  84. package/dist/core/journal.d.ts.map +1 -0
  85. package/dist/core/journal.js +34 -0
  86. package/dist/core/journal.js.map +1 -0
  87. package/dist/core/log.d.ts +8 -0
  88. package/dist/core/log.d.ts.map +1 -0
  89. package/dist/core/log.js +9 -0
  90. package/dist/core/log.js.map +1 -0
  91. package/dist/core/pathGuard.d.ts +3 -0
  92. package/dist/core/pathGuard.d.ts.map +1 -0
  93. package/dist/core/pathGuard.js +18 -0
  94. package/dist/core/pathGuard.js.map +1 -0
  95. package/dist/core/paths.d.ts +11 -0
  96. package/dist/core/paths.d.ts.map +1 -0
  97. package/dist/core/paths.js +22 -0
  98. package/dist/core/paths.js.map +1 -0
  99. package/dist/core/validate.d.ts +8 -0
  100. package/dist/core/validate.d.ts.map +1 -0
  101. package/dist/core/validate.js +27 -0
  102. package/dist/core/validate.js.map +1 -0
  103. package/dist/index.d.ts +3 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +23 -0
  106. package/dist/index.js.map +1 -0
  107. package/docs/decisions.md +55 -0
  108. package/package.json +39 -0
  109. package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
  110. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
  111. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
  112. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
  113. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/index.ts +4 -0
  114. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
  115. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
  116. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
  117. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
  118. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
  119. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
  120. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
  121. package/recipes/audio-recorder/recipe.json +22 -0
  122. package/recipes/audio-recorder@latest.zip +0 -0
  123. package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
  124. package/recipes/charts/apps/native/src/features/charts/README.md +185 -0
  125. package/recipes/charts/apps/native/src/features/charts/app/preview.tsx +223 -0
  126. package/recipes/charts/apps/native/src/features/charts/components/area-chart.tsx +40 -0
  127. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +143 -0
  128. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +196 -0
  129. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +65 -0
  130. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +143 -0
  131. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +246 -0
  132. package/recipes/charts/apps/native/src/features/charts/components/index.ts +10 -0
  133. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +308 -0
  134. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +180 -0
  135. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +188 -0
  136. package/recipes/charts/apps/native/src/features/charts/components/stacked-area-chart.tsx +265 -0
  137. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +322 -0
  138. package/recipes/charts/apps/native/src/features/charts/data/mock-data.ts +183 -0
  139. package/recipes/charts/apps/native/src/features/charts/types/index.ts +66 -0
  140. package/recipes/charts/recipe.json +22 -0
  141. package/recipes/charts@latest.zip +0 -0
  142. package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
  143. package/recipes/chatbot/apps/native/src/features/chatbot/app/index.tsx +302 -0
  144. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
  145. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-input-bar.tsx +469 -0
  146. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
  147. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +246 -0
  148. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
  149. package/recipes/chatbot/apps/native/src/features/chatbot/components/image-preview-list.tsx +115 -0
  150. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
  151. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
  152. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
  153. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
  154. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-list.tsx +173 -0
  155. package/recipes/chatbot/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
  156. package/recipes/chatbot/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
  157. package/recipes/chatbot/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
  158. package/recipes/chatbot/apps/native/src/features/chatbot/constants/models.ts +20 -0
  159. package/recipes/chatbot/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
  160. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +143 -0
  161. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-config.ts +664 -0
  162. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +359 -0
  163. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
  164. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-conversation.ts +79 -0
  165. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
  166. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
  167. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +207 -0
  168. package/recipes/chatbot/apps/native/src/features/chatbot/models/index.ts +86 -0
  169. package/recipes/chatbot/apps/native/src/features/chatbot/models/models.ts +162 -0
  170. package/recipes/chatbot/apps/native/src/features/chatbot/models/providers.ts +62 -0
  171. package/recipes/chatbot/apps/native/src/features/chatbot/models/types.ts +40 -0
  172. package/recipes/chatbot/apps/native/src/features/chatbot/services/file-uploader.ts +238 -0
  173. package/recipes/chatbot/apps/native/src/features/chatbot/services/message-handler-service.ts +180 -0
  174. package/recipes/chatbot/apps/native/src/features/chatbot/types/index.ts +60 -0
  175. package/recipes/chatbot/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
  176. package/recipes/chatbot/recipe.json +22 -0
  177. package/recipes/chatbot@latest.zip +0 -0
  178. package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
  179. package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
  180. package/recipes/image-generator/apps/native/src/features/image-generator/app/_layout.tsx +25 -0
  181. package/recipes/image-generator/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
  182. package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +237 -0
  183. package/recipes/image-generator/apps/native/src/features/image-generator/components/gallery-image.tsx +26 -0
  184. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
  185. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +210 -0
  186. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
  187. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
  188. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
  189. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +93 -0
  190. package/recipes/image-generator/apps/native/src/features/image-generator/models/models.ts +66 -0
  191. package/recipes/image-generator/apps/native/src/features/image-generator/services/image-gallery-service.ts +98 -0
  192. package/recipes/image-generator/apps/native/src/features/image-generator/services/image-save-service.ts +121 -0
  193. package/recipes/image-generator/recipe.json +22 -0
  194. package/recipes/image-generator@latest.zip +0 -0
  195. package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
  196. package/recipes/quiz/apps/native/src/features/quiz/components/question.tsx +67 -0
  197. package/recipes/quiz/apps/native/src/features/quiz/config.ts +11 -0
  198. package/recipes/quiz/apps/native/src/features/quiz/index.tsx +133 -0
  199. package/recipes/quiz/recipe.json +22 -0
  200. package/recipes/quiz@latest.zip +0 -0
  201. package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
  202. package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +108 -0
  203. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/animated-number.tsx +102 -0
  204. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/calorie-card.tsx +66 -0
  205. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/circular-progress.tsx +97 -0
  206. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/floating-add-button.tsx +27 -0
  207. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/macro-card.tsx +80 -0
  208. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/promo-banner.tsx +98 -0
  209. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/recently-logged.tsx +64 -0
  210. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/week-calendar.tsx +68 -0
  211. package/recipes/tracker-app/recipe.json +22 -0
  212. package/recipes/tracker-app@latest.zip +0 -0
  213. package/recipes/upload-all.sh +32 -0
  214. package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +27 -0
  215. package/recipes/voice-bot/apps/native/src/features/voice-bot/README.md +185 -0
  216. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/conversation-status.tsx +76 -0
  217. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/index.ts +4 -0
  218. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/message-input.tsx +98 -0
  219. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-bot-screen.tsx +173 -0
  220. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-controls.tsx +73 -0
  221. package/recipes/voice-bot/apps/native/src/features/voice-bot/index.ts +3 -0
  222. package/recipes/voice-bot/apps/native/src/features/voice-bot/services/index.ts +1 -0
  223. package/recipes/voice-bot/apps/native/src/features/voice-bot/services/use-voice-bot.ts +161 -0
  224. package/recipes/voice-bot/apps/native/src/features/voice-bot/types.ts +29 -0
  225. package/recipes/voice-bot/recipe.json +22 -0
  226. package/recipes/voice-bot@latest.zip +0 -0
  227. package/scripts/create-recipes.mjs +189 -0
  228. package/src/commands/add.ts +183 -0
  229. package/src/commands/devices.ts +38 -0
  230. package/src/commands/doctor.ts +67 -0
  231. package/src/commands/list.ts +45 -0
  232. package/src/commands/login.ts +24 -0
  233. package/src/commands/logout.ts +15 -0
  234. package/src/commands/remove.ts +78 -0
  235. package/src/core/__tests__/journal.test.ts +119 -0
  236. package/src/core/__tests__/validate.test.ts +64 -0
  237. package/src/core/archive.ts +69 -0
  238. package/src/core/auth.ts +103 -0
  239. package/src/core/codemod.ts +211 -0
  240. package/src/core/fsx.ts +80 -0
  241. package/src/core/http.ts +136 -0
  242. package/src/core/journal.ts +64 -0
  243. package/src/core/log.ts +9 -0
  244. package/src/core/pathGuard.ts +22 -0
  245. package/src/core/paths.ts +33 -0
  246. package/src/core/validate.ts +44 -0
  247. package/src/index.ts +27 -0
  248. package/test-critical-cases.mjs +258 -0
  249. package/tsconfig.json +21 -0
  250. package/vitest.config.mts +12 -0
@@ -0,0 +1,102 @@
1
+ import React, { useMemo, useRef, useState } from 'react';
2
+ import { StyleSheet } from 'react-native';
3
+ import { AnimatedRollingNumber } from 'react-native-animated-rolling-numbers';
4
+ import {
5
+ Easing,
6
+ ReduceMotion,
7
+ runOnJS,
8
+ useAnimatedReaction,
9
+ useSharedValue,
10
+ withTiming,
11
+ } from 'react-native-reanimated';
12
+
13
+ import { Text } from '@/components/ui';
14
+
15
+ interface AnimatedNumberProps {
16
+ value: number;
17
+ fontSize?: number;
18
+ fontWeight?: string;
19
+ color: string;
20
+ duration?: number;
21
+ mode?: 'rolling' | 'tween';
22
+ decimals?: number;
23
+ }
24
+
25
+ function AnimatedNumber({
26
+ value,
27
+ fontSize = 48,
28
+ fontWeight = 'bold',
29
+ color,
30
+ duration = 1000,
31
+ mode = 'rolling',
32
+ decimals = 0,
33
+ }: AnimatedNumberProps) {
34
+ const displayRef = useRef(value);
35
+ const [display, setDisplay] = useState(value);
36
+ const sv = useSharedValue(displayRef.current);
37
+
38
+ // Start animation when value changes
39
+ React.useEffect(() => {
40
+ sv.value = withTiming(value, {
41
+ duration,
42
+ easing: Easing.out(Easing.cubic),
43
+ });
44
+ displayRef.current = value;
45
+ }, [value, duration, sv]);
46
+
47
+ // Throttled UI updates to reduce JS pressure when many instances
48
+ const throttleMs = 16; // ~60fps ceiling
49
+ const lastTs = useRef(0);
50
+ useAnimatedReaction(
51
+ () => sv.value,
52
+ (v) => {
53
+ const now = Date.now();
54
+ if (now - lastTs.current >= throttleMs) {
55
+ lastTs.current = now;
56
+ runOnJS(setDisplay)(Number(v));
57
+ }
58
+ },
59
+ [],
60
+ );
61
+
62
+ const textStyle = useMemo(
63
+ () => [styles.number, { fontSize, fontWeight: fontWeight as any, color }],
64
+ [fontSize, fontWeight, color],
65
+ );
66
+
67
+ const spinningAnimationConfig = useMemo(
68
+ () => ({
69
+ duration,
70
+ reduceMotion: ReduceMotion.Never,
71
+ easing: Easing.out(Easing.cubic),
72
+ }),
73
+ [duration],
74
+ );
75
+
76
+ if (mode === 'tween') {
77
+ return (
78
+ <Text style={textStyle} className="">
79
+ {display.toFixed(decimals)}
80
+ </Text>
81
+ );
82
+ }
83
+
84
+ return (
85
+ <AnimatedRollingNumber
86
+ value={value}
87
+ useGrouping={false}
88
+ enableCompactNotation={false}
89
+ compactToFixed={0}
90
+ textStyle={textStyle}
91
+ spinningAnimationConfig={spinningAnimationConfig}
92
+ />
93
+ );
94
+ }
95
+
96
+ export default React.memo(AnimatedNumber);
97
+
98
+ const styles = StyleSheet.create({
99
+ number: {
100
+ textAlign: 'left',
101
+ },
102
+ });
@@ -0,0 +1,66 @@
1
+ import { Ionicons } from '@expo/vector-icons';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { Text } from '@/components/ui';
6
+ import { useThemeConfig } from '@/lib/use-theme-config';
7
+
8
+ import AnimatedNumber from './animated-number';
9
+ import CircularProgress from './circular-progress';
10
+
11
+ interface CalorieCardProps {
12
+ calories: number;
13
+ progress: number;
14
+ }
15
+
16
+ export default function CalorieCard({ calories, progress }: CalorieCardProps) {
17
+ const theme = useThemeConfig();
18
+
19
+ return (
20
+ <View
21
+ className="mb-4 flex-row items-center justify-between rounded-2xl border p-6"
22
+ style={{
23
+ backgroundColor: theme.colors.card,
24
+ borderColor: theme.colors.border,
25
+ shadowColor: theme.colors.foreground,
26
+ shadowOffset: { width: 0, height: 2 },
27
+ shadowOpacity: 0.1,
28
+ shadowRadius: 8,
29
+ elevation: 4,
30
+ }}
31
+ >
32
+ <View className="flex-1">
33
+ <View className="flex-row items-baseline">
34
+ <AnimatedNumber
35
+ value={calories}
36
+ fontSize={48}
37
+ fontWeight="800"
38
+ color={theme.colors.foreground}
39
+ duration={1500}
40
+ />
41
+ </View>
42
+ <Text
43
+ className="text-base font-medium"
44
+ style={{ color: theme.colors.mutedForeground }}
45
+ >
46
+ Calories left
47
+ </Text>
48
+ </View>
49
+ <View className="ml-5">
50
+ <CircularProgress
51
+ size={80}
52
+ strokeWidth={8}
53
+ progress={progress}
54
+ color={theme.colors.primary}
55
+ backgroundColor={theme.colors.muted}
56
+ duration={2000}
57
+ delay={300}
58
+ >
59
+ <View className="items-center justify-center">
60
+ <Ionicons name="flame" size={24} color={theme.colors.warning} />
61
+ </View>
62
+ </CircularProgress>
63
+ </View>
64
+ </View>
65
+ );
66
+ }
@@ -0,0 +1,97 @@
1
+ import { Canvas, Path as SkPath, Skia } from '@shopify/react-native-skia';
2
+ import type React from 'react';
3
+ import { useEffect, useMemo, useState } from 'react';
4
+ import { type LayoutChangeEvent, View as UIView } from 'react-native';
5
+
6
+ interface CircularProgressProps {
7
+ size: number;
8
+ strokeWidth: number;
9
+ progress: number; // 0..100
10
+ color: string;
11
+ backgroundColor?: string;
12
+ children?: React.ReactNode;
13
+ duration?: number;
14
+ delay?: number;
15
+ }
16
+
17
+ export default function CircularProgress({
18
+ size,
19
+ strokeWidth,
20
+ progress,
21
+ color,
22
+ backgroundColor = '#f0f0f0',
23
+ children,
24
+ duration = 1500,
25
+ delay = 0,
26
+ }: CircularProgressProps) {
27
+ const [containerSize, setContainerSize] = useState(size);
28
+ const [p, setP] = useState(1);
29
+
30
+ const onLayout = (e: LayoutChangeEvent) => {
31
+ const { width, height } = e.nativeEvent.layout;
32
+ const s = Math.min(width || size, height || size) || size;
33
+ if (s > 0) setContainerSize(s);
34
+ };
35
+
36
+ useEffect(() => {
37
+ let raf: number;
38
+ let start: number | null = null;
39
+ const easeInOutCubic = (t: number) =>
40
+ t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
41
+ const tick = (ts: number) => {
42
+ if (start == null) start = ts + (delay || 0);
43
+ const elapsed = Math.max(0, ts - start);
44
+ const t = Math.min(1, elapsed / (duration || 1500));
45
+ setP(easeInOutCubic(t) * (progress / 100));
46
+ if (t < 1) raf = requestAnimationFrame(tick);
47
+ };
48
+ setP(0);
49
+ raf = requestAnimationFrame(tick);
50
+ return () => cancelAnimationFrame(raf);
51
+ }, [progress, duration, delay]);
52
+
53
+ const radius = useMemo(
54
+ () => (containerSize - strokeWidth) / 2,
55
+ [containerSize, strokeWidth],
56
+ );
57
+
58
+ const circlePath = useMemo(() => {
59
+ const pth = Skia.Path.Make();
60
+ pth.addCircle(containerSize / 2, containerSize / 2, radius);
61
+ return pth;
62
+ }, [containerSize, radius]);
63
+
64
+ return (
65
+ <UIView
66
+ className="relative"
67
+ style={{ width: size, height: size }}
68
+ onLayout={onLayout}
69
+ >
70
+ <Canvas style={{ width: containerSize, height: containerSize }}>
71
+ {/* Track */}
72
+ <SkPath
73
+ path={circlePath}
74
+ color={backgroundColor}
75
+ style="stroke"
76
+ strokeWidth={strokeWidth}
77
+ opacity={1}
78
+ />
79
+ {/* Progress arc */}
80
+ <SkPath
81
+ path={circlePath}
82
+ color={color}
83
+ style="stroke"
84
+ strokeWidth={strokeWidth}
85
+ start={0}
86
+ end={p}
87
+ strokeCap="round"
88
+ />
89
+ </Canvas>
90
+ {children && (
91
+ <UIView className="absolute inset-0 items-center justify-center">
92
+ {children}
93
+ </UIView>
94
+ )}
95
+ </UIView>
96
+ );
97
+ }
@@ -0,0 +1,27 @@
1
+ import { Ionicons } from '@expo/vector-icons';
2
+ import React from 'react';
3
+ import { TouchableOpacity } from 'react-native';
4
+
5
+ import { useThemeConfig } from '@/lib/use-theme-config';
6
+
7
+ export default function FloatingAddButton() {
8
+ const theme = useThemeConfig();
9
+
10
+ const handlePress = () => {
11
+ // Handle add food functionality
12
+ console.log('Add food pressed');
13
+ };
14
+
15
+ return (
16
+ <TouchableOpacity
17
+ className="absolute right-5 size-14 items-center justify-center rounded-full shadow-lg"
18
+ style={{
19
+ backgroundColor: theme.colors.primary,
20
+ bottom: 100, // Fixed positioning
21
+ }}
22
+ onPress={handlePress}
23
+ >
24
+ <Ionicons name="add" size={24} color={theme.colors.primaryForeground} />
25
+ </TouchableOpacity>
26
+ );
27
+ }
@@ -0,0 +1,80 @@
1
+ import type React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import { Text } from '@/components/ui';
5
+ import { useThemeConfig } from '@/lib/use-theme-config';
6
+
7
+ import AnimatedNumber from './animated-number';
8
+ import CircularProgress from './circular-progress';
9
+
10
+ interface MacroCardProps {
11
+ value: number;
12
+ unit: string;
13
+ label: string;
14
+ progress: number;
15
+ color: string;
16
+ icon: React.ReactNode;
17
+ delay?: number;
18
+ }
19
+
20
+ export default function MacroCard({
21
+ value,
22
+ unit,
23
+ label,
24
+ progress,
25
+ color,
26
+ icon,
27
+ delay = 0,
28
+ }: MacroCardProps) {
29
+ const theme = useThemeConfig();
30
+
31
+ return (
32
+ <View
33
+ className="flex-1 items-start rounded-2xl border p-4"
34
+ style={{
35
+ backgroundColor: theme.colors.card,
36
+ borderColor: theme.colors.border,
37
+ shadowColor: theme.colors.foreground,
38
+ shadowOffset: { width: 0, height: 2 },
39
+ shadowOpacity: 0.1,
40
+ shadowRadius: 8,
41
+ elevation: 4,
42
+ }}
43
+ >
44
+ <View className="mb-1 flex-row items-baseline">
45
+ <AnimatedNumber
46
+ value={value}
47
+ fontSize={32}
48
+ fontWeight="700"
49
+ color={theme.colors.foreground}
50
+ duration={1200}
51
+ />
52
+ <Text
53
+ className="ml-1 text-xl font-semibold"
54
+ style={{ color: theme.colors.foreground }}
55
+ >
56
+ {unit}
57
+ </Text>
58
+ </View>
59
+ <Text
60
+ className="mb-4 text-sm"
61
+ style={{ color: theme.colors.mutedForeground }}
62
+ >
63
+ {label}
64
+ </Text>
65
+ <View className="self-center">
66
+ <CircularProgress
67
+ size={60}
68
+ strokeWidth={6}
69
+ progress={progress}
70
+ color={color}
71
+ backgroundColor={theme.colors.muted}
72
+ duration={1800}
73
+ delay={delay}
74
+ >
75
+ <View className="items-center justify-center">{icon}</View>
76
+ </CircularProgress>
77
+ </View>
78
+ </View>
79
+ );
80
+ }
@@ -0,0 +1,98 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+
4
+ import { Text } from '@/components/ui';
5
+ import { useThemeConfig } from '@/lib/use-theme-config';
6
+
7
+ export default function PromoBanner() {
8
+ const [timeLeft, setTimeLeft] = useState({
9
+ hours: 71,
10
+ minutes: 48,
11
+ seconds: 12,
12
+ });
13
+ const theme = useThemeConfig();
14
+
15
+ useEffect(() => {
16
+ const timer = setInterval(() => {
17
+ setTimeLeft((prev) => {
18
+ if (prev.seconds > 0) {
19
+ return { ...prev, seconds: prev.seconds - 1 };
20
+ }
21
+ if (prev.minutes > 0) {
22
+ return { ...prev, minutes: prev.minutes - 1, seconds: 59 };
23
+ }
24
+ if (prev.hours > 0) {
25
+ return { hours: prev.hours - 1, minutes: 59, seconds: 59 };
26
+ }
27
+ return prev;
28
+ });
29
+ }, 1000);
30
+
31
+ return () => clearInterval(timer);
32
+ }, []);
33
+
34
+ return (
35
+ <View
36
+ className="my-4 flex-row items-center justify-between rounded-2xl border p-5"
37
+ style={{
38
+ backgroundColor: theme.colors.muted,
39
+ borderColor: theme.colors.border,
40
+ shadowColor: theme.colors.foreground,
41
+ shadowOffset: { width: 0, height: 2 },
42
+ shadowOpacity: 0.1,
43
+ shadowRadius: 8,
44
+ elevation: 4,
45
+ }}
46
+ >
47
+ <View className="flex-1">
48
+ <View
49
+ className="mb-2 self-start rounded-2xl border-2 px-3 py-1.5"
50
+ style={{
51
+ borderColor: theme.colors.destructive,
52
+ backgroundColor: theme.colors.card,
53
+ }}
54
+ >
55
+ <Text
56
+ className="text-sm font-bold"
57
+ style={{ color: theme.colors.destructive }}
58
+ >
59
+ 80% off
60
+ </Text>
61
+ </View>
62
+ <Text
63
+ className="text-lg font-bold leading-5"
64
+ style={{ color: theme.colors.foreground }}
65
+ >
66
+ Your trial ends in
67
+ </Text>
68
+ <Text
69
+ className="text-lg font-bold leading-5"
70
+ style={{ color: theme.colors.foreground }}
71
+ >
72
+ 2 days!!
73
+ </Text>
74
+ </View>
75
+ <View className="items-end">
76
+ <View className="mb-3">
77
+ <Text
78
+ className="text-base font-semibold"
79
+ style={{ color: theme.colors.mutedForeground }}
80
+ >
81
+ {timeLeft.hours} : {timeLeft.minutes} : {timeLeft.seconds}
82
+ </Text>
83
+ </View>
84
+ <TouchableOpacity
85
+ className="rounded-2xl px-5 py-3"
86
+ style={{ backgroundColor: theme.colors.primary }}
87
+ >
88
+ <Text
89
+ className="text-sm font-semibold"
90
+ style={{ color: theme.colors.primaryForeground }}
91
+ >
92
+ Resubscribe now
93
+ </Text>
94
+ </TouchableOpacity>
95
+ </View>
96
+ </View>
97
+ );
98
+ }
@@ -0,0 +1,64 @@
1
+ import { Ionicons } from '@expo/vector-icons';
2
+ import React from 'react';
3
+ import { Image, View } from 'react-native';
4
+
5
+ import { Text } from '@/components/ui';
6
+ import { useThemeConfig } from '@/lib/use-theme-config';
7
+
8
+ export default function RecentlyLogged() {
9
+ const theme = useThemeConfig();
10
+
11
+ return (
12
+ <View className="mt-4">
13
+ <Text
14
+ className="mb-4 text-xl font-bold"
15
+ style={{ color: theme.colors.foreground }}
16
+ >
17
+ Recently logged
18
+ </Text>
19
+ <View
20
+ className="flex-row items-center rounded-2xl border p-2 pr-4"
21
+ style={{
22
+ backgroundColor: theme.colors.card,
23
+ borderColor: theme.colors.border,
24
+ shadowColor: theme.colors.foreground,
25
+ shadowOffset: { width: 0, height: 2 },
26
+ shadowOpacity: 0.1,
27
+ shadowRadius: 8,
28
+ elevation: 4,
29
+ }}
30
+ >
31
+ <Image
32
+ source={{
33
+ uri: 'https://images.pexels.com/photos/1435735/pexels-photo-1435735.jpeg?auto=compress&cs=tinysrgb&w=150&h=150&dpr=2',
34
+ }}
35
+ style={{ width: 70, height: 70 }}
36
+ className="mr-3 rounded-xl"
37
+ />
38
+ <View className="flex-1">
39
+ <Text
40
+ className="mb-1.5 text-base font-semibold"
41
+ style={{ color: theme.colors.foreground }}
42
+ >
43
+ Mixed Fruits and...
44
+ </Text>
45
+ <View className="flex-row items-center">
46
+ <Ionicons name="flame" size={16} color={theme.colors.warning} />
47
+ <Text
48
+ className="ml-1 text-sm font-semibold"
49
+ style={{ color: theme.colors.foreground }}
50
+ >
51
+ 300 calories
52
+ </Text>
53
+ </View>
54
+ </View>
55
+ <Text
56
+ className="text-sm font-medium"
57
+ style={{ color: theme.colors.mutedForeground }}
58
+ >
59
+ 12:27 PM
60
+ </Text>
61
+ </View>
62
+ </View>
63
+ );
64
+ }
@@ -0,0 +1,68 @@
1
+ import React, { useState } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+
4
+ import { Text } from '@/components/ui';
5
+ import { useThemeConfig } from '@/lib/use-theme-config';
6
+
7
+ interface Day {
8
+ letter: string;
9
+ number: number;
10
+ isToday?: boolean;
11
+ }
12
+
13
+ const days: Day[] = [
14
+ { letter: 'S', number: 22 },
15
+ { letter: 'S', number: 23 },
16
+ { letter: 'M', number: 24 },
17
+ { letter: 'T', number: 25 },
18
+ { letter: 'W', number: 26 },
19
+ { letter: 'T', number: 27, isToday: true },
20
+ { letter: 'F', number: 28 },
21
+ ];
22
+
23
+ export default function WeekCalendar() {
24
+ const [selectedDay, setSelectedDay] = useState(5); // Thursday 27
25
+ const theme = useThemeConfig();
26
+
27
+ return (
28
+ <View className="mb-6 flex-row justify-between px-1">
29
+ {days.map((day, index) => (
30
+ <TouchableOpacity
31
+ key={index}
32
+ className="items-center justify-center rounded-2xl border-2 border-dashed px-4 py-6"
33
+ style={{
34
+ borderColor:
35
+ index === selectedDay
36
+ ? theme.colors.primary
37
+ : theme.colors.border,
38
+ backgroundColor: 'transparent',
39
+ }}
40
+ onPress={() => setSelectedDay(index)}
41
+ >
42
+ <Text
43
+ className="mb-2 text-xs font-medium"
44
+ style={{
45
+ color:
46
+ index === selectedDay
47
+ ? theme.colors.primary
48
+ : theme.colors.mutedForeground,
49
+ }}
50
+ >
51
+ {day.letter}
52
+ </Text>
53
+ <Text
54
+ className="text-base font-semibold"
55
+ style={{
56
+ color:
57
+ index === selectedDay
58
+ ? theme.colors.primary
59
+ : theme.colors.foreground,
60
+ }}
61
+ >
62
+ {day.number}
63
+ </Text>
64
+ </TouchableOpacity>
65
+ ))}
66
+ </View>
67
+ );
68
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "tracker-app",
3
+ "version": "1.0.0",
4
+ "description": "Track habits and activities",
5
+ "copy": [
6
+ {
7
+ "from": "apps/native/src/app/tracker-app",
8
+ "to": "apps/native/src/app/(root)/(protected)/tracker-app"
9
+ },
10
+ {
11
+ "from": "apps/native/src/features/tracker-app",
12
+ "to": "apps/native/src/features/tracker-app"
13
+ }
14
+ ],
15
+ "nav": {
16
+ "href": "/(root)/(protected)/tracker-app",
17
+ "label": "Tracker",
18
+ "icon": "๐ŸŽ",
19
+ "color": "#06B6D4"
20
+ },
21
+ "target": "native"
22
+ }
Binary file
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+
3
+ echo "๐Ÿ“ค Uploading all recipes to R2..."
4
+ echo ""
5
+
6
+ recipes=(
7
+ "charts"
8
+ "chatbot"
9
+ "voice-bot"
10
+ "image-generator"
11
+ "audio-recorder"
12
+ "quiz"
13
+ "tracker-app"
14
+ )
15
+
16
+ for recipe in "${recipes[@]}"; do
17
+ echo "Uploading ${recipe}@latest.zip..."
18
+ wrangler r2 object put vibefast-recipes/${recipe}@latest.zip --file=${recipe}@latest.zip --remote
19
+ if [ $? -eq 0 ]; then
20
+ echo "โœ“ ${recipe} uploaded"
21
+ else
22
+ echo "โœ— ${recipe} failed"
23
+ fi
24
+ echo ""
25
+ done
26
+
27
+ echo "โœ… Upload complete!"
28
+ echo ""
29
+ echo "๐Ÿงช Test with:"
30
+ echo "cd ../../vibefast-monorepo"
31
+ echo "export VIBEFAST_WORKER_URL=https://vibefast-cli-worker.mzafar611.workers.dev"
32
+ echo "vf list"
@@ -0,0 +1,27 @@
1
+ import { Env } from '@env';
2
+ import { Stack } from 'expo-router';
3
+ import React, { useMemo } from 'react';
4
+
5
+ import { VoiceBotScreen } from '@/features/voice-bot';
6
+
7
+ export default function VoiceBotRoute() {
8
+ const agentId = Env.ELEVENLABS_AGENT_ID;
9
+ const screenOptions = useMemo(
10
+ () => ({
11
+ title: 'Voice Assistant',
12
+ headerShown: true,
13
+ }),
14
+ [],
15
+ );
16
+
17
+ return (
18
+ <>
19
+ <Stack.Screen options={screenOptions} />
20
+ <VoiceBotScreen
21
+ config={{ agentId }}
22
+ title="Voice Assistant"
23
+ subtitle="Start a conversation with your AI assistant"
24
+ />
25
+ </>
26
+ );
27
+ }