vibefast-cli 1.2.1 → 1.3.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 (348) hide show
  1. package/README.md +30 -95
  2. package/dist/__tests__/recipes.test.js +94 -91
  3. package/dist/__tests__/recipes.test.js.map +1 -1
  4. package/dist/commands/add.d.ts.map +1 -1
  5. package/dist/commands/add.js +301 -125
  6. package/dist/commands/add.js.map +1 -1
  7. package/dist/commands/checklist.d.ts.map +1 -1
  8. package/dist/commands/checklist.js +85 -44
  9. package/dist/commands/checklist.js.map +1 -1
  10. package/dist/commands/health.d.ts.map +1 -1
  11. package/dist/commands/health.js +13 -4
  12. package/dist/commands/health.js.map +1 -1
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +118 -26
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/migrate.d.ts +3 -0
  17. package/dist/commands/migrate.d.ts.map +1 -0
  18. package/dist/commands/migrate.js +202 -0
  19. package/dist/commands/migrate.js.map +1 -0
  20. package/dist/commands/remove.d.ts.map +1 -1
  21. package/dist/commands/remove.js +61 -3
  22. package/dist/commands/remove.js.map +1 -1
  23. package/dist/core/auth.d.ts.map +1 -1
  24. package/dist/core/auth.js +20 -18
  25. package/dist/core/auth.js.map +1 -1
  26. package/dist/core/codemod.d.ts +33 -0
  27. package/dist/core/codemod.d.ts.map +1 -1
  28. package/dist/core/codemod.js +116 -0
  29. package/dist/core/codemod.js.map +1 -1
  30. package/dist/core/detect.d.ts.map +1 -1
  31. package/dist/core/detect.js +24 -7
  32. package/dist/core/detect.js.map +1 -1
  33. package/dist/core/journal.d.ts +1 -0
  34. package/dist/core/journal.d.ts.map +1 -1
  35. package/dist/core/journal.js.map +1 -1
  36. package/dist/core/recipes.d.ts.map +1 -1
  37. package/dist/core/recipes.js +25 -7
  38. package/dist/core/recipes.js.map +1 -1
  39. package/dist/index.js +2 -2
  40. package/dist/index.js.map +1 -1
  41. package/docs/architecture.md +50 -0
  42. package/docs/commands.md +78 -0
  43. package/docs/contributing.md +27 -0
  44. package/docs/quickstart.md +50 -0
  45. package/docs/recipes.md +57 -0
  46. package/docs/troubleshooting.md +31 -0
  47. package/package.json +2 -2
  48. package/recipes/0/apps/native/src/components/advanced-ui/timeline/demo.tsx +445 -0
  49. package/recipes/0/apps/native/src/components/advanced-ui/timeline/timeline-view.tsx +355 -0
  50. package/recipes/0/apps/native/src/components/advanced-ui/timeline/types.ts +31 -0
  51. package/recipes/0/recipe.json +18 -0
  52. package/recipes/animated-chip/apps/native/src/components/advanced-ui/chip/demo.tsx +2 -1
  53. package/recipes/animated-chip/recipe.json +5 -2
  54. package/recipes/animated-chip-native@latest.zip +0 -0
  55. package/recipes/animated-chip@latest.zip +0 -0
  56. package/recipes/animated-switch/apps/native/src/components/advanced-ui/switch/demo.tsx +1 -1
  57. package/recipes/animated-switch/recipe.json +5 -2
  58. package/recipes/animated-switch-native@latest.zip +0 -0
  59. package/recipes/animated-switch@latest.zip +0 -0
  60. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
  61. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -2
  62. package/recipes/audio-recorder/recipe.json +7 -2
  63. package/recipes/audio-recorder-native@latest.zip +0 -0
  64. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
  65. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -1
  66. package/recipes/audio-recorder-supabase/recipe.json +12 -16
  67. package/recipes/audio-recorder-supabase-native@latest.zip +0 -0
  68. package/recipes/audio-recorder-supabase@latest.zip +0 -0
  69. package/recipes/audio-recorder@latest.zip +0 -0
  70. package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
  71. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -1
  72. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +3 -1
  73. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -1
  74. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +3 -1
  75. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +3 -1
  76. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +3 -1
  77. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +3 -1
  78. package/recipes/charts/recipe.json +13 -4
  79. package/recipes/charts-native@latest.zip +0 -0
  80. package/recipes/charts@latest.zip +0 -0
  81. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
  82. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +4 -4
  83. package/recipes/chatbot/recipe.json +3 -40
  84. package/recipes/chatbot-native@latest.zip +0 -0
  85. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +4 -1
  86. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
  87. package/recipes/chatbot-supabase/recipe.json +3 -42
  88. package/recipes/chatbot-supabase-native@latest.zip +0 -0
  89. package/recipes/chatbot-supabase@latest.zip +0 -0
  90. package/recipes/chatbot@latest.zip +0 -0
  91. package/recipes/glowing-button/recipe.json +6 -2
  92. package/recipes/glowing-button-native@latest.zip +0 -0
  93. package/recipes/glowing-button@latest.zip +0 -0
  94. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
  95. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
  96. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
  97. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/index.tsx +50 -0
  98. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
  99. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/results.tsx +2 -0
  100. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
  101. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +2 -2
  102. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/camera.tsx +72 -65
  103. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +65 -47
  104. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading-screen.tsx +43 -2
  105. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading.tsx +34 -1
  106. package/recipes/image-analysis/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +83 -2
  107. package/recipes/image-analysis/recipe.json +11 -19
  108. package/recipes/image-analysis-native@latest.zip +0 -0
  109. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
  110. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
  111. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
  112. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/index.tsx +50 -0
  113. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
  114. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/results.tsx +2 -0
  115. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
  116. package/recipes/image-analysis-supabase/recipe.json +10 -37
  117. package/recipes/image-analysis-supabase-native@latest.zip +0 -0
  118. package/recipes/image-analysis-supabase@latest.zip +0 -0
  119. package/recipes/image-analysis@latest.zip +0 -0
  120. package/recipes/image-analyzer/apps/native/src/app/(root)/(protected)/image-analyzer/index.tsx +2 -0
  121. package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
  122. package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
  123. package/recipes/image-generator/recipe.json +8 -18
  124. package/recipes/image-generator-native@latest.zip +0 -0
  125. package/recipes/image-generator-supabase/recipe.json +6 -35
  126. package/recipes/image-generator-supabase-native@latest.zip +0 -0
  127. package/recipes/image-generator-supabase@latest.zip +0 -0
  128. package/recipes/image-generator@latest.zip +0 -0
  129. package/recipes/ios-widget/recipe.json +18 -119
  130. package/recipes/ios-widget-native@latest.zip +0 -0
  131. package/recipes/ios-widget@latest.zip +0 -0
  132. package/recipes/number-stepper/apps/native/src/components/advanced-ui/stepper/demo.tsx +1 -1
  133. package/recipes/number-stepper/recipe.json +5 -2
  134. package/recipes/number-stepper-native@latest.zip +0 -0
  135. package/recipes/number-stepper@latest.zip +0 -0
  136. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +11 -18
  137. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +5 -7
  138. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +9 -7
  139. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +8 -7
  140. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +6 -5
  141. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +4 -3
  142. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +6 -5
  143. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +5 -7
  144. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +7 -6
  145. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +5 -7
  146. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +8 -7
  147. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +6 -5
  148. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +5 -6
  149. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +5 -4
  150. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +5 -7
  151. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +7 -6
  152. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +4 -3
  153. package/recipes/onboarding/recipe.json +9 -6
  154. package/recipes/onboarding-native@latest.zip +0 -0
  155. package/recipes/onboarding@latest.zip +0 -0
  156. package/recipes/payments/apps/native/src/app/paywall/index.tsx +74 -0
  157. package/recipes/payments/apps/native/src/app/paywall/local.tsx +25 -0
  158. package/recipes/payments/apps/native/src/app/paywall/remote.tsx +23 -0
  159. package/recipes/payments/packages/backend/convex/payments.ts +21 -3
  160. package/recipes/payments/recipe.json +14 -34
  161. package/recipes/payments-native@latest.zip +0 -0
  162. package/recipes/payments-supabase/apps/native/src/app/paywall/index.tsx +74 -0
  163. package/recipes/payments-supabase/apps/native/src/app/paywall/local.tsx +25 -0
  164. package/recipes/payments-supabase/apps/native/src/app/paywall/remote.tsx +23 -0
  165. package/recipes/payments-supabase/recipe.json +16 -23
  166. package/recipes/payments-supabase-native@latest.zip +0 -0
  167. package/recipes/payments-supabase@latest.zip +0 -0
  168. package/recipes/payments@latest.zip +0 -0
  169. package/recipes/posthog/apps/native/src/components/analytics/navigation-tracker.tsx +14 -0
  170. package/recipes/posthog/apps/native/src/lib/hooks/use-navigation-analytics.ts +44 -0
  171. package/recipes/posthog/apps/native/src/providers/posthog-provider.tsx +51 -0
  172. package/recipes/posthog/recipe.json +60 -0
  173. package/recipes/posthog-native@latest.zip +0 -0
  174. package/recipes/progress-circle/apps/native/src/components/advanced-ui/progress-bars/progress-circle-page.tsx +1 -1
  175. package/recipes/progress-circle/recipe.json +5 -2
  176. package/recipes/progress-circle-native@latest.zip +0 -0
  177. package/recipes/progress-circle@latest.zip +0 -0
  178. package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
  179. package/recipes/quiz/recipe.json +9 -6
  180. package/recipes/quiz-native@latest.zip +0 -0
  181. package/recipes/quiz@latest.zip +0 -0
  182. package/recipes/screen-kits/apps/native/src/app/screen-kits/_layout.tsx +12 -0
  183. package/recipes/screen-kits/apps/native/src/app/screen-kits/index.tsx +114 -0
  184. package/recipes/screen-kits/apps/native/src/features/screen-kits/index.ts +1 -0
  185. package/recipes/screen-kits/apps/native/src/features/screen-kits/types.ts +28 -0
  186. package/recipes/screen-kits/recipe.json +26 -0
  187. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/_layout.tsx +12 -0
  188. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/home.tsx +5 -0
  189. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/index.tsx +5 -0
  190. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-complete.tsx +5 -0
  191. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-fail.tsx +5 -0
  192. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson.tsx +5 -0
  193. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/skill-tree.tsx +5 -0
  194. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/duo-button.tsx +174 -0
  195. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/skill-button.tsx +186 -0
  196. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/xp-header.tsx +115 -0
  197. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/constants.ts +89 -0
  198. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/index.ts +3 -0
  199. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/home-screen.tsx +225 -0
  200. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-complete-screen.tsx +485 -0
  201. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-fail-screen.tsx +105 -0
  202. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-screen.tsx +384 -0
  203. package/recipes/screen-kits-duolingo/recipe.json +58 -0
  204. package/recipes/screen-kits-duolingo-native@latest.zip +0 -0
  205. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/_layout.tsx +45 -0
  206. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/asset-detail.tsx +3 -0
  207. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/notifications.tsx +3 -0
  208. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/receive.tsx +3 -0
  209. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/send.tsx +3 -0
  210. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/swap.tsx +3 -0
  211. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/wallet.tsx +3 -0
  212. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/ActionButtons.tsx +78 -0
  213. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/AssetRow.tsx +94 -0
  214. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/BalanceCard.tsx +118 -0
  215. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/constants.ts +85 -0
  216. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/asset-detail.tsx +378 -0
  217. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/notifications.tsx +210 -0
  218. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/receive-modal.tsx +317 -0
  219. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/send-modal.tsx +420 -0
  220. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/swap-modal.tsx +363 -0
  221. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/wallet-dashboard.tsx +281 -0
  222. package/recipes/screen-kits-finance/recipe.json +46 -0
  223. package/recipes/screen-kits-finance-native@latest.zip +0 -0
  224. package/recipes/screen-kits-fitness/apps/native/assets/sounds/timer-beep.wav +0 -0
  225. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/_layout.tsx +10 -0
  226. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/index.tsx +6 -0
  227. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/timer.tsx +3 -0
  228. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/workout.tsx +3 -0
  229. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-components.tsx +500 -0
  230. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-settings-modal.tsx +352 -0
  231. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/workout-card.tsx +105 -0
  232. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/constants.ts +189 -0
  233. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/hooks/use-timer.ts +307 -0
  234. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/index.ts +1 -0
  235. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/timer-screen.tsx +278 -0
  236. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/workout-dashboard.tsx +350 -0
  237. package/recipes/screen-kits-fitness/recipe.json +63 -0
  238. package/recipes/screen-kits-fitness-native@latest.zip +0 -0
  239. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/habits.tsx +1 -0
  240. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/kanban.tsx +1 -0
  241. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/routes.ts +4 -0
  242. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/AddTaskModal.tsx +246 -0
  243. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/DraggableTaskCard.tsx +92 -0
  244. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/KanbanColumn.tsx +238 -0
  245. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/TaskCard.tsx +144 -0
  246. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/add-habit-modal.tsx +271 -0
  247. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/constants.ts +295 -0
  248. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/kanban-utils.ts +62 -0
  249. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/habit-tracker.tsx +1160 -0
  250. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/kanban-board.tsx +432 -0
  251. package/recipes/screen-kits-habits/recipe.json +52 -0
  252. package/recipes/screen-kits-habits-native@latest.zip +0 -0
  253. package/recipes/screen-kits-native@latest.zip +0 -0
  254. package/recipes/sentry/apps/native/src/providers/sentry-provider.tsx +64 -0
  255. package/recipes/sentry/recipe.json +39 -0
  256. package/recipes/sentry-native@latest.zip +0 -0
  257. package/recipes/swipe-slider/apps/native/src/components/advanced-ui/sliders/swipe-slider-page.tsx +1 -1
  258. package/recipes/swipe-slider/recipe.json +5 -2
  259. package/recipes/swipe-slider-native@latest.zip +0 -0
  260. package/recipes/swipe-slider@latest.zip +0 -0
  261. package/recipes/timeline/apps/native/src/components/advanced-ui/timeline/demo.tsx +2 -1
  262. package/recipes/timeline/recipe.json +5 -2
  263. package/recipes/timeline-native@latest.zip +0 -0
  264. package/recipes/timeline@latest.zip +0 -0
  265. package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
  266. package/recipes/tracker-app/recipe.json +10 -7
  267. package/recipes/tracker-app-native@latest.zip +0 -0
  268. package/recipes/tracker-app@latest.zip +0 -0
  269. package/recipes/upload-all.sh +8 -31
  270. package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +56 -0
  271. package/recipes/voice-bot/recipe.json +31 -7
  272. package/recipes/voice-bot-native@latest.zip +0 -0
  273. package/recipes/voice-bot@latest.zip +0 -0
  274. package/recipes/wake-word/apps/native/src/app/{(root)/(protected)/test-wake-word.tsx → test-wake-word.tsx} +43 -4
  275. package/recipes/wake-word/recipe.json +16 -26
  276. package/recipes/wake-word-native@latest.zip +0 -0
  277. package/recipes/wake-word@latest.zip +0 -0
  278. package/scripts/create-advanced-ui-recipes.sh +46 -19
  279. package/scripts/create-recipes.mjs +471 -117
  280. package/scripts/package-recipes.mjs +76 -0
  281. package/scripts/publish-all.sh +6 -2
  282. package/CHANGELOG.md +0 -198
  283. package/docs/archive/AUTO-DETECT-DEPS.md +0 -607
  284. package/docs/archive/FINAL-PACKAGE-STRATEGY.md +0 -583
  285. package/docs/archive/FINAL-SIMPLE-PLAN.md +0 -487
  286. package/docs/archive/FINAL-STATUS.md +0 -144
  287. package/docs/archive/FLOW-DIAGRAM.md +0 -1629
  288. package/docs/archive/GOTCHAS-AND-RISKS.md +0 -801
  289. package/docs/archive/IMPLEMENTATION-PLAN.md +0 -1360
  290. package/docs/archive/PLAN.md +0 -453
  291. package/docs/archive/PRODUCTION-READINESS.md +0 -684
  292. package/docs/archive/PRODUCTION-TEST-RESULTS.md +0 -465
  293. package/docs/archive/SIMPLIFIED-PLAN.md +0 -578
  294. package/docs/archive/STATUS.md +0 -199
  295. package/docs/archive/SUCCESS.md +0 -259
  296. package/docs/archive/TEST-SUMMARY.md +0 -261
  297. package/docs/archive/TESTING-CHECKLIST.md +0 -450
  298. package/docs/archive/USER-MODIFICATIONS.md +0 -448
  299. package/docs/decisions.md +0 -55
  300. package/docs/manual-testing.md +0 -91
  301. package/docs/next-steps.md +0 -12
  302. package/recipes/README.md +0 -156
  303. package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +0 -369
  304. package/recipes/chatbot/apps/native/src/api-client/chatbot.ts +0 -83
  305. package/recipes/chatbot/packages/backend/convex/agents.ts +0 -115
  306. package/recipes/chatbot/packages/backend/convex/tools/index.ts +0 -18
  307. package/recipes/chatbot/packages/backend/convex/tools/knowledgeRetrieval.ts +0 -97
  308. package/recipes/chatbot/packages/backend/convex/tools/tavilySearch.ts +0 -83
  309. package/recipes/chatbot/packages/backend/convex/tools/userProfile.ts +0 -72
  310. package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +0 -515
  311. package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +0 -243
  312. package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +0 -327
  313. package/recipes/image-analysis/apps/native/src/api-client/image-analyzer.ts +0 -62
  314. package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +0 -132
  315. package/recipes/image-generator/apps/native/src/api-client/image-generator.ts +0 -34
  316. package/recipes/payments/apps/native/src/api-client/payments.ts +0 -44
  317. package/recipes/payments-supabase/packages/backend/src/services/payments.ts +0 -201
  318. package/recipes/posthog.json +0 -47
  319. package/recipes/revenuecat.json +0 -43
  320. package/recipes/sentry.json +0 -47
  321. package/recipes/wake-word/apps/native/assets/vosk-model/README.md +0 -103
  322. package/recipes/wake-word/apps/native/scripts/download-vosk-model.mjs +0 -127
  323. /package/recipes/{audio-recorder/apps/native/src/app/(root)/(protected) → audio-recorder-supabase/apps/native/src/app}/audio-recorder/index.tsx +0 -0
  324. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/AppIntent.swift +0 -0
  325. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png +0 -0
  326. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png +0 -0
  327. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png +0 -0
  328. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png +0 -0
  329. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png +0 -0
  330. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png +0 -0
  331. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png +0 -0
  332. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png +0 -0
  333. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png +0 -0
  334. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png +0 -0
  335. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png +0 -0
  336. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png +0 -0
  337. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png +0 -0
  338. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png +0 -0
  339. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  340. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png +0 -0
  341. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/CalorieTrackerWidget.swift +0 -0
  342. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/HabitTrackerWidget.swift +0 -0
  343. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Info.plist +0 -0
  344. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/WidgetLiveActivity.swift +0 -0
  345. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/expo-target.config.js +0 -0
  346. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/generated.entitlements +0 -0
  347. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/index.swift +0 -0
  348. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/widgets.swift +0 -0
@@ -1,16 +1,43 @@
1
+ // vibefast license: c1e9fcd2-muhammad
1
2
  import { Feather } from '@expo/vector-icons';
2
3
  import React, { useCallback, useState } from 'react';
3
4
  import {
4
5
  type ImageStyle,
5
6
  Pressable,
7
+ ScrollView,
8
+ Text,
6
9
  type TextStyle,
7
10
  View,
8
11
  type ViewStyle,
9
12
  } from 'react-native';
10
- import SyntaxHighlighter from 'react-native-syntax-highlighter';
13
+ import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
14
+ import bash from 'react-syntax-highlighter/dist/esm/languages/hljs/bash';
15
+ import css from 'react-syntax-highlighter/dist/esm/languages/hljs/css';
16
+ import js from 'react-syntax-highlighter/dist/esm/languages/hljs/javascript';
17
+ import json from 'react-syntax-highlighter/dist/esm/languages/hljs/json';
18
+ import python from 'react-syntax-highlighter/dist/esm/languages/hljs/python';
19
+ import ts from 'react-syntax-highlighter/dist/esm/languages/hljs/typescript';
20
+ import xml from 'react-syntax-highlighter/dist/esm/languages/hljs/xml';
11
21
 
12
22
  import { translate } from '@/lib';
13
23
 
24
+ // Register languages for the Light build
25
+ SyntaxHighlighter.registerLanguage('javascript', js);
26
+ SyntaxHighlighter.registerLanguage('js', js);
27
+ SyntaxHighlighter.registerLanguage('typescript', ts);
28
+ SyntaxHighlighter.registerLanguage('ts', ts);
29
+ SyntaxHighlighter.registerLanguage('tsx', ts);
30
+ SyntaxHighlighter.registerLanguage('jsx', js);
31
+ SyntaxHighlighter.registerLanguage('python', python);
32
+ SyntaxHighlighter.registerLanguage('py', python);
33
+ SyntaxHighlighter.registerLanguage('json', json);
34
+ SyntaxHighlighter.registerLanguage('bash', bash);
35
+ SyntaxHighlighter.registerLanguage('sh', bash);
36
+ SyntaxHighlighter.registerLanguage('shell', bash);
37
+ SyntaxHighlighter.registerLanguage('css', css);
38
+ SyntaxHighlighter.registerLanguage('html', xml);
39
+ SyntaxHighlighter.registerLanguage('xml', xml);
40
+
14
41
  type CodeBlockProps = {
15
42
  containerStyle: ViewStyle | TextStyle | ImageStyle;
16
43
  content: string;
@@ -26,44 +53,51 @@ type CodeBlockProps = {
26
53
  onCopyCode: (code: string) => Promise<void>;
27
54
  };
28
55
 
56
+ /**
57
+ * Custom renderer for React Native - converts syntax highlighter output to Text components
58
+ */
59
+ function createNativeRenderer(fontFamily: string, fontSize: number) {
60
+ return function renderer({
61
+ rows,
62
+ stylesheet,
63
+ }: {
64
+ rows: any[];
65
+ stylesheet: Record<string, any>;
66
+ }) {
67
+ return rows.map((row, i) => {
68
+ const children = row.children?.map((child: any, j: number) => {
69
+ if (child.type === 'text') {
70
+ return child.value;
71
+ }
72
+ const className = child.properties?.className?.[0] || '';
73
+ const style = stylesheet[className] || {};
74
+ return (
75
+ <Text
76
+ key={j}
77
+ style={{
78
+ fontFamily,
79
+ fontSize,
80
+ color: style.color,
81
+ fontWeight: style.fontWeight,
82
+ fontStyle: style.fontStyle,
83
+ }}
84
+ >
85
+ {child.children?.map((c: any) => c.value).join('') || ''}
86
+ </Text>
87
+ );
88
+ });
89
+
90
+ return (
91
+ <Text key={i} style={{ fontFamily, fontSize }}>
92
+ {children}
93
+ </Text>
94
+ );
95
+ });
96
+ };
97
+ }
98
+
29
99
  /**
30
100
  * CodeBlock component for rendering syntax-highlighted code with collapse/expand functionality.
31
- *
32
- * Features:
33
- * - Syntax highlighting using react-native-syntax-highlighter
34
- * - Copy to clipboard functionality
35
- * - Collapse/expand animation with FlashList preparation
36
- * - Smooth 220ms easeInEaseOut animation
37
- * - Independent animation for multiple code blocks
38
- *
39
- * Requirements addressed:
40
- * - 9.1: Prepare FlashList for layout animation before collapse
41
- * - 9.2: Animate height change over 220ms with easeInEaseOut
42
- * - 9.3: Animate each code block independently
43
- * - 9.4: Restore full content with same animation timing
44
- * - 9.5: Complete animation without interruption during scroll
45
- *
46
- * @param props - CodeBlock component props
47
- * @returns Rendered code block with syntax highlighting and controls
48
- *
49
- * @example
50
- * ```tsx
51
- * <CodeBlock
52
- * containerStyle={styles.code_block}
53
- * content="const hello = 'world';"
54
- * language="javascript"
55
- * codeSyntaxTheme={atomOneDark}
56
- * monospaceFontFamily="Menlo"
57
- * subtleText="#888"
58
- * codeContentStyle={styles.codeContent}
59
- * codeActionsContainerStyle={styles.actions}
60
- * codeActionButtonBaseStyle={styles.button}
61
- * codeToggleButtonSpacingStyle={styles.spacing}
62
- * codeContentContainerStyle={styles.container}
63
- * onCopyCode={copyToClipboard}
64
- * onPrepareLayoutAnimation={prepareFlashList}
65
- * />
66
- * ```
67
101
  */
68
102
  export const CodeBlock = React.memo(function CodeBlock({
69
103
  containerStyle,
@@ -81,14 +115,12 @@ export const CodeBlock = React.memo(function CodeBlock({
81
115
  }: CodeBlockProps) {
82
116
  const [isCollapsed, setIsCollapsed] = useState(false);
83
117
 
84
- /**
85
- * Toggle collapsed state without animation.
86
- * LayoutAnimation causes scroll jitter, so we disable it.
87
- */
88
118
  const toggleCollapsed = useCallback(() => {
89
119
  setIsCollapsed((prev) => !prev);
90
120
  }, []);
91
121
 
122
+ const renderer = createNativeRenderer(monospaceFontFamily, 15);
123
+
92
124
  return (
93
125
  <View
94
126
  style={[
@@ -146,18 +178,19 @@ export const CodeBlock = React.memo(function CodeBlock({
146
178
  pointerEvents={isCollapsed ? 'none' : 'auto'}
147
179
  >
148
180
  {isCollapsed ? null : (
149
- <SyntaxHighlighter
150
- language={language.length > 0 ? language : 'plaintext'}
151
- style={codeSyntaxTheme}
152
- highlighter="hljs"
153
- fontFamily={monospaceFontFamily}
154
- fontSize={15}
155
- PreTag={View}
156
- CodeTag={View}
157
- customStyle={codeContentStyle}
158
- >
159
- {content}
160
- </SyntaxHighlighter>
181
+ <ScrollView horizontal showsHorizontalScrollIndicator={false}>
182
+ <SyntaxHighlighter
183
+ language={language.length > 0 ? language : 'plaintext'}
184
+ style={codeSyntaxTheme}
185
+ renderer={renderer}
186
+ customStyle={{
187
+ ...codeContentStyle,
188
+ backgroundColor: 'transparent',
189
+ }}
190
+ >
191
+ {content}
192
+ </SyntaxHighlighter>
193
+ </ScrollView>
161
194
  )}
162
195
  </View>
163
196
  </View>
@@ -1,7 +1,7 @@
1
1
  {
2
- "name": "chatbot",
2
+ "name": "chatbot-supabase",
3
3
  "version": "1.0.0",
4
- "description": "AI-powered chat assistant with Supabase backend",
4
+ "description": "AI-powered chat assistant with Supabase",
5
5
  "copy": [
6
6
  {
7
7
  "from": "apps/native/src/app/chatbot",
@@ -11,10 +11,6 @@
11
11
  "from": "apps/native/src/features/chatbot",
12
12
  "to": "apps/native/src/features/chatbot"
13
13
  },
14
- {
15
- "from": "apps/native/src/api-client/supabase/chatbot.ts",
16
- "to": "apps/native/src/api-client/supabase/chatbot.ts"
17
- },
18
14
  {
19
15
  "from": "packages/backend/supabase/functions/chat-stream",
20
16
  "to": "packages/backend/supabase/functions/chat-stream"
@@ -22,27 +18,17 @@
22
18
  {
23
19
  "from": "packages/backend/supabase/migrations/chatbot.sql",
24
20
  "to": "packages/backend/supabase/migrations/chatbot.sql"
25
- },
26
- {
27
- "from": "packages/backend/src/services/conversations.ts",
28
- "to": "packages/backend/src/services/conversations.ts"
29
- },
30
- {
31
- "from": "packages/backend/src/services/messages.ts",
32
- "to": "packages/backend/src/services/messages.ts"
33
21
  }
34
22
  ],
35
23
  "nav": {
36
24
  "href": "/(root)/(protected)/chatbot",
37
- "label": "AI Chatbot",
25
+ "label": "AI Chatbot (Supabase)",
38
26
  "icon": "💬",
39
27
  "color": "#F43F5E"
40
28
  },
41
29
  "target": "native",
42
30
  "dependencies": {
43
31
  "expo": [
44
- "@supabase/supabase-js",
45
- "@tanstack/react-query",
46
32
  "expo-clipboard",
47
33
  "markdown-it",
48
34
  "react-native-markdown-display",
@@ -50,30 +36,5 @@
50
36
  "react-native-reanimated",
51
37
  "react-native-safe-area-context"
52
38
  ]
53
- },
54
- "env": [
55
- {
56
- "key": "OPENAI_API_KEY",
57
- "description": "OpenAI API key for chat completions",
58
- "example": "sk-...",
59
- "link": "https://platform.openai.com/api-keys",
60
- "file": "packages/backend/supabase/.env",
61
- "required": true
62
- }
63
- ],
64
- "manualSteps": [
65
- {
66
- "title": "Apply Supabase migration",
67
- "description": "Run: cd packages/backend && supabase db push",
68
- "content": "supabase db push"
69
- },
70
- {
71
- "title": "Deploy Edge Function",
72
- "description": "Run: cd packages/backend && supabase functions deploy chat-stream",
73
- "content": "supabase functions deploy chat-stream"
74
- }
75
- ],
76
- "postInstall": {
77
- "message": "📦 Remember to run 'supabase db push' and 'supabase functions deploy chat-stream'"
78
39
  }
79
40
  }
Binary file
Binary file
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "glowing-button",
3
3
  "version": "1.0.0",
4
- "description": "Animated glowing button with multiple presets",
4
+ "description": "Advanced UI component: glowing-button",
5
5
  "target": "native",
6
6
  "copy": [
7
7
  {
@@ -10,6 +10,10 @@
10
10
  }
11
11
  ],
12
12
  "dependencies": {
13
- "expo": ["react-native-reanimated"]
13
+ "expo": [
14
+ "react-native-animated-glow",
15
+ "react-native-reanimated",
16
+ "react-native-gesture-handler"
17
+ ]
14
18
  }
15
19
  }
Binary file
@@ -0,0 +1,5 @@
1
+ import { Slot } from 'expo-router';
2
+
3
+ export default function AnalysisLayout() {
4
+ return <Slot />;
5
+ }
@@ -0,0 +1,50 @@
1
+ import { Redirect, useLocalSearchParams } from 'expo-router';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { FocusAwareStatusBar, Text } from '@/components/ui';
6
+ import { DynamicAnalysisOptionsScreen } from '@/features/image-analyzer/app/analysis-options-screen';
7
+ import { getAnalysisFlowConfigSafe } from '@/features/image-analyzer/config/master-analysis-config';
8
+ import { translate } from '@/lib';
9
+ import { useThemeConfig } from '@/lib/use-theme-config';
10
+
11
+ /**
12
+ * Dynamic analysis options route that loads the appropriate configuration
13
+ * based on the type parameter
14
+ */
15
+ export default function DynamicAnalysisOptionsRoute() {
16
+ const { type } = useLocalSearchParams<{ type: string }>();
17
+ const theme = useThemeConfig();
18
+
19
+ if (!type || typeof type !== 'string') {
20
+ return <Redirect href="/(protected)/(tabs)" />;
21
+ }
22
+
23
+ const config = getAnalysisFlowConfigSafe(type);
24
+
25
+ if (!config) {
26
+ // Invalid analysis type, redirect to home with a user-friendly message
27
+ return (
28
+ <View
29
+ style={{
30
+ flex: 1,
31
+ backgroundColor: theme.colors.background,
32
+ justifyContent: 'center',
33
+ alignItems: 'center',
34
+ padding: 20,
35
+ }}
36
+ >
37
+ <FocusAwareStatusBar />
38
+ <Text className="mb-4 text-center text-lg font-medium">
39
+ {translate('common.invalid_analysis_type')}
40
+ </Text>
41
+ <Text className="mb-6 text-center text-muted-foreground">
42
+ {translate('common.redirecting_home')}
43
+ </Text>
44
+ <Redirect href="/(protected)/(tabs)" />
45
+ </View>
46
+ );
47
+ }
48
+
49
+ return <DynamicAnalysisOptionsScreen config={config} />;
50
+ }
@@ -0,0 +1,2 @@
1
+ // Re-export the camera screen
2
+ export { default } from '@/features/image-analyzer/app/camera';
@@ -0,0 +1,50 @@
1
+ import { Redirect, useLocalSearchParams } from 'expo-router';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { FocusAwareStatusBar, Text } from '@/components/ui';
6
+ import { ImageCaptureScreen } from '@/features/image-analyzer/app/image-capture-screen';
7
+ import { getAnalysisFlowConfigSafe } from '@/features/image-analyzer/config/master-analysis-config';
8
+ import { translate } from '@/lib';
9
+ import { useThemeConfig } from '@/lib/use-theme-config';
10
+
11
+ /**
12
+ * Dynamic analysis route that loads the appropriate configuration
13
+ * based on the type parameter
14
+ */
15
+ export default function DynamicAnalysisScreen() {
16
+ const { type } = useLocalSearchParams<{ type: string }>();
17
+ const theme = useThemeConfig();
18
+
19
+ if (!type || typeof type !== 'string') {
20
+ return <Redirect href="/(protected)/(tabs)" />;
21
+ }
22
+
23
+ const config = getAnalysisFlowConfigSafe(type);
24
+
25
+ if (!config) {
26
+ // Invalid analysis type, redirect to home with a user-friendly message
27
+ return (
28
+ <View
29
+ style={{
30
+ flex: 1,
31
+ backgroundColor: theme.colors.background,
32
+ justifyContent: 'center',
33
+ alignItems: 'center',
34
+ padding: 20,
35
+ }}
36
+ >
37
+ <FocusAwareStatusBar />
38
+ <Text className="mb-4 text-center text-lg font-medium">
39
+ {translate('common.invalid_analysis_type')}
40
+ </Text>
41
+ <Text className="mb-6 text-center text-muted-foreground">
42
+ {translate('common.redirecting_home')}
43
+ </Text>
44
+ <Redirect href="/(protected)/(tabs)" />
45
+ </View>
46
+ );
47
+ }
48
+
49
+ return <ImageCaptureScreen config={config} />;
50
+ }
@@ -0,0 +1,50 @@
1
+ import { Redirect, useLocalSearchParams } from 'expo-router';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { FocusAwareStatusBar, Text } from '@/components/ui';
6
+ import { LoadingScreen } from '@/features/image-analyzer/app/loading-screen';
7
+ import { getAnalysisFlowConfigSafe } from '@/features/image-analyzer/config/master-analysis-config';
8
+ import { translate } from '@/lib';
9
+ import { useThemeConfig } from '@/lib/use-theme-config';
10
+
11
+ /**
12
+ * Dynamic loading route that loads the appropriate configuration
13
+ * based on the type parameter
14
+ */
15
+ export default function DynamicLoadingRoute() {
16
+ const { type } = useLocalSearchParams<{ type: string }>();
17
+ const theme = useThemeConfig();
18
+
19
+ if (!type || typeof type !== 'string') {
20
+ return <Redirect href="/(protected)/(tabs)" />;
21
+ }
22
+
23
+ const config = getAnalysisFlowConfigSafe(type);
24
+
25
+ if (!config) {
26
+ // Invalid analysis type, redirect to home with a user-friendly message
27
+ return (
28
+ <View
29
+ style={{
30
+ flex: 1,
31
+ backgroundColor: theme.colors.background,
32
+ justifyContent: 'center',
33
+ alignItems: 'center',
34
+ padding: 20,
35
+ }}
36
+ >
37
+ <FocusAwareStatusBar />
38
+ <Text className="mb-4 text-center text-lg font-medium">
39
+ {translate('common.invalid_analysis_type')}
40
+ </Text>
41
+ <Text className="mb-6 text-center text-muted-foreground">
42
+ {translate('common.redirecting_home')}
43
+ </Text>
44
+ <Redirect href="/(protected)/(tabs)" />
45
+ </View>
46
+ );
47
+ }
48
+
49
+ return <LoadingScreen config={config} />;
50
+ }
@@ -0,0 +1,2 @@
1
+ // Re-export the results screen
2
+ export { default } from '@/features/image-analyzer/app/results';
@@ -0,0 +1,3 @@
1
+ import TraitDetailsScreen from '@/features/image-analyzer/app/trait-details';
2
+
3
+ export default TraitDetailsScreen;
@@ -88,7 +88,7 @@ export function DynamicAnalysisOptionsScreen({
88
88
  config,
89
89
  }: DynamicAnalysisOptionsProps) {
90
90
  const router = useRouter();
91
- const { standard } = useNavigationOptions();
91
+ const { scrollable } = useNavigationOptions();
92
92
  const params = useLocalSearchParams();
93
93
 
94
94
  const imageUris: string[] = useMemo(
@@ -145,7 +145,7 @@ export function DynamicAnalysisOptionsScreen({
145
145
  <>
146
146
  <Stack.Screen
147
147
  options={{
148
- ...standard,
148
+ ...scrollable,
149
149
  title: config.name,
150
150
  headerBackButtonDisplayMode: 'generic',
151
151
  }}
@@ -2,7 +2,13 @@ import { MaterialIcons } from '@expo/vector-icons';
2
2
  import { type CameraType, CameraView, useCameraPermissions } from 'expo-camera';
3
3
  import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
4
4
  import React, { useCallback, useRef, useState } from 'react';
5
- import { ActivityIndicator, Alert, TouchableOpacity, View } from 'react-native';
5
+ import {
6
+ ActivityIndicator,
7
+ Alert,
8
+ StyleSheet,
9
+ TouchableOpacity,
10
+ View,
11
+ } from 'react-native';
6
12
 
7
13
  import { Button, Image, Text } from '@/components/ui';
8
14
  import { useCameraCaptureStore } from '@/features/image-analyzer/hooks/use-image-analysis';
@@ -11,7 +17,6 @@ type CameraScreenParams = {
11
17
  stepId: string;
12
18
  stepLabel: string;
13
19
  stepDescription: string;
14
- guideText: string;
15
20
  };
16
21
 
17
22
  /**
@@ -28,11 +33,12 @@ export default function CameraScreen() {
28
33
  const [facing, setFacing] = useState<CameraType>('back');
29
34
  const [capturedImageUri, setCapturedImageUri] = useState<string | null>(null);
30
35
  const [isCapturing, setIsCapturing] = useState(false);
36
+ const [isCameraReady, setIsCameraReady] = useState(false);
31
37
  const cameraRef = useRef<CameraView>(null);
32
38
 
33
39
  // Handle photo capture
34
40
  const handleTakePhoto = useCallback(async () => {
35
- if (!cameraRef.current || isCapturing) return;
41
+ if (!cameraRef.current || isCapturing || !isCameraReady) return;
36
42
 
37
43
  try {
38
44
  setIsCapturing(true);
@@ -49,7 +55,7 @@ export default function CameraScreen() {
49
55
  } finally {
50
56
  setIsCapturing(false);
51
57
  }
52
- }, [isCapturing]);
58
+ }, [isCapturing, isCameraReady]);
53
59
 
54
60
  // Handle retake
55
61
  const handleRetake = useCallback(() => {
@@ -147,74 +153,75 @@ export default function CameraScreen() {
147
153
  <View className="flex-1 bg-black">
148
154
  <CameraView
149
155
  ref={cameraRef}
150
- style={{ flex: 1 }}
156
+ style={StyleSheet.absoluteFill}
151
157
  facing={facing}
152
158
  mode="picture"
153
- >
154
- {/* Header with step info */}
155
- <View className="absolute inset-x-0 top-12 px-6">
156
- <View className="rounded-xl bg-black/70 p-4">
157
- <Text className="text-center text-lg font-bold text-white">
158
- {params.stepLabel}
159
- </Text>
160
- <Text className="text-center text-sm text-white/80">
161
- 📸 {params.guideText}
162
- </Text>
163
- </View>
159
+ onCameraReady={() => setIsCameraReady(true)}
160
+ />
161
+
162
+ {/* Header with step info */}
163
+ <View className="absolute inset-x-0 top-12 px-6">
164
+ <View className="rounded-xl bg-black/70 p-4">
165
+ <Text className="text-center text-lg font-bold text-white">
166
+ {params.stepLabel}
167
+ </Text>
168
+ <Text className="text-center text-sm text-white/80">
169
+ 📸 {params.stepDescription}
170
+ </Text>
164
171
  </View>
172
+ </View>
165
173
 
166
- {/* Frame guide overlay */}
167
- <View className="absolute inset-0 items-center justify-center">
168
- <View className="relative size-80">
169
- {/* Frame */}
170
- <View className="absolute inset-0 rounded-2xl border-2 border-white/60" />
171
-
172
- {/* Corner guides */}
173
- <View className="absolute left-2 top-2 size-6 border-l-4 border-t-4 border-white" />
174
- <View className="absolute right-2 top-2 size-6 border-r-4 border-t-4 border-white" />
175
- <View className="absolute bottom-2 left-2 size-6 border-b-4 border-l-4 border-white" />
176
- <View className="absolute bottom-2 right-2 size-6 border-b-4 border-r-4 border-white" />
177
-
178
- {/* Center guide */}
179
- <View className="absolute inset-0 items-center justify-center">
180
- <View className="h-1 w-8 bg-white/60" />
181
- <View className="absolute h-8 w-1 bg-white/60" />
182
- </View>
174
+ {/* Frame guide overlay */}
175
+ <View className="absolute inset-0 items-center justify-center">
176
+ <View className="relative size-80">
177
+ {/* Frame */}
178
+ <View className="absolute inset-0 rounded-2xl border-2 border-white/60" />
179
+
180
+ {/* Corner guides */}
181
+ <View className="absolute left-2 top-2 size-6 border-l-4 border-t-4 border-white" />
182
+ <View className="absolute right-2 top-2 size-6 border-r-4 border-t-4 border-white" />
183
+ <View className="absolute bottom-2 left-2 size-6 border-b-4 border-l-4 border-white" />
184
+ <View className="absolute bottom-2 right-2 size-6 border-b-4 border-r-4 border-white" />
185
+
186
+ {/* Center guide */}
187
+ <View className="absolute inset-0 items-center justify-center">
188
+ <View className="h-1 w-8 bg-white/60" />
189
+ <View className="absolute h-8 w-1 bg-white/60" />
183
190
  </View>
184
191
  </View>
192
+ </View>
185
193
 
186
- {/* Controls */}
187
- <View className="absolute inset-x-0 bottom-12 flex-row items-center justify-center px-6">
188
- {/* Close button */}
189
- <TouchableOpacity
190
- onPress={() => router.back()}
191
- className="absolute left-6 size-12 items-center justify-center rounded-full bg-black/50"
192
- >
193
- <Text className="text-xl text-white">✕</Text>
194
- </TouchableOpacity>
195
-
196
- {/* Shutter button */}
197
- <TouchableOpacity
198
- onPress={handleTakePhoto}
199
- disabled={isCapturing}
200
- className="size-20 items-center justify-center rounded-full border-4 border-white bg-white/20"
201
- >
202
- {isCapturing ? (
203
- <ActivityIndicator size="large" color="white" />
204
- ) : (
205
- <View className="size-16 rounded-full bg-white" />
206
- )}
207
- </TouchableOpacity>
208
-
209
- {/* Flip camera button */}
210
- <TouchableOpacity
211
- onPress={toggleCameraFacing}
212
- className="absolute right-6 size-12 items-center justify-center rounded-full bg-black/50"
213
- >
214
- <MaterialIcons name="cameraswitch" size={24} color="white" />
215
- </TouchableOpacity>
216
- </View>
217
- </CameraView>
194
+ {/* Controls */}
195
+ <View className="absolute inset-x-0 bottom-12 flex-row items-center justify-center px-6">
196
+ {/* Close button */}
197
+ <TouchableOpacity
198
+ onPress={() => router.back()}
199
+ className="absolute left-6 size-12 items-center justify-center rounded-full bg-black/50"
200
+ >
201
+ <Text className="text-xl text-white">✕</Text>
202
+ </TouchableOpacity>
203
+
204
+ {/* Shutter button */}
205
+ <TouchableOpacity
206
+ onPress={handleTakePhoto}
207
+ disabled={isCapturing || !isCameraReady}
208
+ className="size-20 items-center justify-center rounded-full border-4 border-white bg-white/20"
209
+ >
210
+ {isCapturing ? (
211
+ <ActivityIndicator size="large" color="white" />
212
+ ) : (
213
+ <View className="size-16 rounded-full bg-white" />
214
+ )}
215
+ </TouchableOpacity>
216
+
217
+ {/* Flip camera button */}
218
+ <TouchableOpacity
219
+ onPress={toggleCameraFacing}
220
+ className="absolute right-6 size-12 items-center justify-center rounded-full bg-black/50"
221
+ >
222
+ <MaterialIcons name="cameraswitch" size={24} color="white" />
223
+ </TouchableOpacity>
224
+ </View>
218
225
  </View>
219
226
  </>
220
227
  );