@mediacubeco/expo-template-fsd 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/.claude/commands/git-commit.md +164 -0
  2. package/.claude/rules/architecture.md +38 -0
  3. package/.claude/rules/{prettier-eslint-typescript.mdc → prettier-eslint-typescript.md} +5 -10
  4. package/.claude/settings.json +2 -2
  5. package/.claude/skills/api/SKILL.md +362 -0
  6. package/.claude/skills/api/references/client/overview.md +106 -0
  7. package/.claude/skills/api/references/hooks/index.ts +3 -0
  8. package/.claude/skills/api/references/hooks/use-api-health.ts +25 -0
  9. package/.claude/skills/api/references/hooks/use-api-post.ts +46 -0
  10. package/.claude/skills/api/references/hooks/use-api-posts.ts +24 -0
  11. package/.claude/skills/api/references/mock/post.mock.ts +29 -0
  12. package/.claude/skills/{generate-api-model/references → api/references/model}/entities/common.ts +5 -2
  13. package/.claude/skills/api/references/model/resources/common.ts +9 -0
  14. package/.claude/skills/api/references/queries/health.ts +14 -0
  15. package/.claude/skills/api/references/queries/index.ts +2 -0
  16. package/.claude/skills/api/references/queries/post.ts +23 -0
  17. package/.claude/skills/api/references/repository/health/health.ts +11 -0
  18. package/.claude/skills/api/references/repository/health/health.types.ts +25 -0
  19. package/.claude/skills/api/references/repository/health/index.ts +2 -0
  20. package/.claude/skills/api/references/repository/post/index.ts +9 -0
  21. package/.claude/skills/api/references/repository/post/post.ts +34 -0
  22. package/.claude/skills/api/references/repository/post/post.types.ts +61 -0
  23. package/.claude/skills/code-style/SKILL.md +1025 -1
  24. package/.claude/skills/code-style/references/components/payout-speed-option/index.ts +2 -0
  25. package/.claude/skills/code-style/references/components/payout-speed-option/payout-speed-option.styles.ts +76 -0
  26. package/.claude/skills/code-style/references/components/payout-speed-option/payout-speed-option.tsx +58 -0
  27. package/.claude/skills/code-style/references/components/payout-speed-option/payout-speed-option.types.ts +22 -0
  28. package/.claude/skills/code-style/references/components/post/index.ts +2 -0
  29. package/.claude/skills/code-style/references/components/post/post.styles.ts +19 -0
  30. package/.claude/skills/code-style/references/components/post/post.tsx +21 -0
  31. package/.claude/skills/code-style/references/components/post/post.types.ts +9 -0
  32. package/.claude/skills/code-style/references/components/wrap/index.ts +2 -0
  33. package/.claude/skills/code-style/references/components/wrap/wrap.styles.ts +15 -0
  34. package/.claude/skills/code-style/references/components/wrap/wrap.tsx +31 -0
  35. package/.claude/skills/code-style/references/components/wrap/wrap.types.ts +10 -0
  36. package/.claude/skills/code-style/references/hooks/use-posts.ts +37 -0
  37. package/.claude/skills/code-style/references/pages/post/index.ts +4 -0
  38. package/.claude/skills/code-style/references/pages/post/post-details/index.ts +1 -0
  39. package/.claude/skills/code-style/references/pages/post/post-details/post-details.tsx +13 -0
  40. package/.claude/skills/code-style/references/pages/post/post-guide/index.ts +1 -0
  41. package/.claude/skills/code-style/references/pages/post/post-guide/post-guide.tsx +17 -0
  42. package/.claude/skills/code-style/references/pages/post/post-list/index.ts +1 -0
  43. package/.claude/skills/code-style/references/pages/post/post-list/post-list.styles.ts +17 -0
  44. package/.claude/skills/code-style/references/pages/post/post-list/post-list.tsx +25 -0
  45. package/.claude/skills/code-style/references/pages/post/post-share/index.ts +1 -0
  46. package/.claude/skills/code-style/references/pages/post/post-share/post-share.tsx +13 -0
  47. package/.claude/skills/code-style/references/routes/(stack)/_layout.tsx +18 -0
  48. package/.claude/skills/code-style/references/routes/(stack)/details.tsx +8 -0
  49. package/.claude/skills/code-style/references/routes/(stack)/guide.tsx +8 -0
  50. package/.claude/skills/code-style/references/routes/(stack)/index.tsx +8 -0
  51. package/.claude/skills/code-style/references/routes/(stack)/share.tsx +8 -0
  52. package/.claude/skills/code-style/references/routes/(tabs)/(post-details)/index.tsx +8 -0
  53. package/.claude/skills/code-style/references/routes/(tabs)/(post-list)/index.tsx +8 -0
  54. package/.claude/skills/code-style/references/routes/(tabs)/_layout.tsx +50 -0
  55. package/.claude/skills/code-style/references/routes/_app.tsx +20 -0
  56. package/.claude/skills/code-style/references/routes/guide.tsx +8 -0
  57. package/.claude/skills/code-style/references/routes/share.tsx +8 -0
  58. package/.claude/skills/code-style/references/store/use-post-draft-store.ts +62 -0
  59. package/.claude/skills/design-style/SKILL.md +320 -0
  60. package/.env +3 -1
  61. package/.env.example +3 -1
  62. package/CLAUDE.md +5 -11
  63. package/app.json +6 -3
  64. package/axios.d.ts +5 -0
  65. package/env.d.ts +3 -1
  66. package/package.json +33 -40
  67. package/patches/react-native-screens+4.25.2.patch +118 -0
  68. package/react-query.d.ts +13 -0
  69. package/src/app/(root)/(home)/_layout.tsx +2 -2
  70. package/src/app/(root)/(home)/index.tsx +2 -2
  71. package/src/app/(root)/(settings)/_layout.tsx +2 -2
  72. package/src/app/(root)/(settings)/index.tsx +2 -2
  73. package/src/app/(root)/_layout.tsx +35 -32
  74. package/src/pages/home/home-main.tsx +3 -7
  75. package/src/pages/settings/settings-main.tsx +3 -7
  76. package/src/shared/assets/fonts/index.ts +3 -3
  77. package/src/shared/assets/fonts/sf-pro-text-bold.ttf +0 -0
  78. package/src/shared/assets/fonts/sf-pro-text-regular.ttf +0 -0
  79. package/src/shared/assets/fonts/sf-pro-text-semibold.ttf +0 -0
  80. package/src/shared/assets/icons/back.tsx +21 -0
  81. package/src/shared/assets/icons/close.tsx +21 -0
  82. package/src/shared/assets/icons/common.ts +8 -0
  83. package/src/shared/assets/icons/default.tsx +44 -0
  84. package/src/shared/assets/icons/index.ts +13 -1
  85. package/src/shared/assets/icons/refresh.tsx +23 -0
  86. package/src/shared/assets/icons/share.tsx +38 -0
  87. package/src/shared/assets/icons/type.ts +7 -0
  88. package/src/shared/assets/translations/index.ts +4 -4
  89. package/src/shared/constants/config.ts +13 -0
  90. package/src/shared/constants/environment.ts +16 -4
  91. package/src/shared/constants/index.ts +1 -0
  92. package/src/shared/hooks/index.ts +1 -4
  93. package/src/shared/hooks/use-compose.ts +23 -0
  94. package/src/shared/lib/api/api.client.ts +157 -0
  95. package/src/shared/lib/api/api.provider.tsx +14 -36
  96. package/src/shared/lib/api/api.ts +1 -5
  97. package/src/shared/lib/api/api.types.ts +6 -3
  98. package/src/shared/lib/api/hooks/index.ts +1 -0
  99. package/src/shared/lib/api/index.ts +2 -3
  100. package/src/shared/lib/api/models/api-instance/api-instance.client.ts +50 -0
  101. package/src/shared/lib/api/models/api-instance/api-instance.ts +30 -82
  102. package/src/shared/lib/api/models/api-instance/api-instance.types.ts +16 -18
  103. package/src/shared/lib/api/models/api-instance/api-instance.utils.ts +13 -20
  104. package/src/shared/lib/api/models/api-instance/index.ts +3 -0
  105. package/src/shared/lib/api/queries/index.ts +1 -0
  106. package/src/shared/lib/api/repositories/index.ts +1 -1
  107. package/src/shared/lib/localization/constants/index.ts +16 -5
  108. package/src/shared/lib/localization/index.ts +5 -1
  109. package/src/shared/lib/navigation/hooks/index.ts +8 -3
  110. package/src/shared/{hooks/use-breakpoints.ts → lib/navigation/hooks/use-navigation-breakpoints.ts} +2 -5
  111. package/src/shared/lib/navigation/hooks/use-navigation-dimensions.ts +12 -0
  112. package/src/shared/lib/navigation/hooks/use-navigation-options.tsx +175 -0
  113. package/src/shared/lib/navigation/hooks/{use-navigation.ts → use-navigation-route.ts} +2 -2
  114. package/src/shared/lib/navigation/hooks/use-navigation-safe-area.ts +61 -0
  115. package/src/shared/lib/navigation/hooks/use-navigation-tabs-native.ts +10 -0
  116. package/src/shared/lib/navigation/hooks/use-navigation-tabs.tsx +10 -0
  117. package/src/shared/lib/navigation/hooks/use-navigation-transition.ts +27 -0
  118. package/src/shared/lib/navigation/index.ts +11 -4
  119. package/src/shared/lib/navigation/navigation-tabs-native.context.tsx +5 -0
  120. package/src/shared/lib/navigation/navigation-tabs-native.provider.tsx +17 -0
  121. package/src/shared/lib/navigation/navigation-tabs.context.tsx +10 -0
  122. package/src/shared/lib/navigation/navigation-tabs.provider.tsx +22 -0
  123. package/src/shared/lib/navigation/navigation.provider.tsx +6 -1
  124. package/src/shared/lib/storage/index.ts +1 -1
  125. package/src/shared/lib/storage/storage.provider.tsx +4 -0
  126. package/src/shared/lib/storage/storage.ts +29 -25
  127. package/src/shared/lib/theme/constants/animations.ts +26 -0
  128. package/src/shared/lib/theme/constants/colors.ts +336 -43
  129. package/src/shared/lib/theme/constants/delays.ts +1 -1
  130. package/src/shared/lib/theme/constants/durations.ts +1 -1
  131. package/src/shared/lib/theme/constants/fonts.ts +2 -1
  132. package/src/shared/lib/theme/constants/index.ts +42 -20
  133. package/src/shared/lib/theme/constants/shadows.ts +7 -25
  134. package/src/shared/lib/theme/constants/sizes.ts +11 -2
  135. package/src/shared/lib/theme/constants/transparencies.ts +1 -1
  136. package/src/shared/lib/theme/hooks/use-theme-setup.ts +3 -1
  137. package/src/shared/lib/theme/index.ts +10 -1
  138. package/src/shared/lib/theme/theme.provider.tsx +45 -19
  139. package/src/shared/lib/theme/theme.scope.tsx +43 -0
  140. package/src/shared/lib/theme/theme.types.ts +15 -3
  141. package/src/shared/lib/theme/utils/color.ts +81 -0
  142. package/src/shared/lib/theme/utils/index.ts +2 -0
  143. package/src/shared/lib/theme/utils/snapshot.ts +17 -0
  144. package/src/shared/lib/theme/utils/storage.ts +5 -2
  145. package/src/shared/services/browser/browser.ts +66 -0
  146. package/src/shared/services/browser/index.ts +1 -0
  147. package/src/shared/services/cookies/cookies.ts +73 -0
  148. package/src/shared/services/cookies/index.ts +1 -0
  149. package/src/shared/services/index.ts +5 -0
  150. package/src/shared/services/linking/index.ts +1 -0
  151. package/src/shared/services/linking/linking.ts +22 -0
  152. package/src/shared/services/share/index.ts +1 -0
  153. package/src/shared/services/share/share.ts +28 -0
  154. package/src/shared/services/universal-links/index.ts +104 -0
  155. package/src/shared/services/universal-links/universal-links.ts +25 -0
  156. package/src/shared/services/universal-links/universal-links.types.ts +5 -0
  157. package/src/shared/ui/atoms/blur/blur.tsx +9 -4
  158. package/src/shared/ui/atoms/blur/blur.types.ts +1 -1
  159. package/src/shared/ui/atoms/blur-progress/blur-progress.styles.ts +16 -0
  160. package/src/shared/ui/atoms/blur-progress/blur-progress.tsx +30 -0
  161. package/src/shared/ui/atoms/blur-progress/blur-progress.types.tsx +5 -0
  162. package/src/shared/ui/atoms/blur-progress/index.ts +1 -0
  163. package/src/shared/ui/atoms/glass/glass.tsx +13 -5
  164. package/src/shared/ui/atoms/glass/glass.types.ts +1 -1
  165. package/src/shared/ui/atoms/icon/icon.styles.ts +82 -0
  166. package/src/shared/ui/atoms/icon/icon.tsx +21 -0
  167. package/src/shared/ui/atoms/icon/icon.types.ts +23 -0
  168. package/src/shared/ui/atoms/icon/index.ts +2 -0
  169. package/src/shared/ui/atoms/index.ts +7 -0
  170. package/src/shared/ui/atoms/skeleton/index.ts +2 -0
  171. package/src/shared/ui/atoms/skeleton/skeleton.styles.ts +69 -0
  172. package/src/shared/ui/atoms/skeleton/skeleton.tsx +26 -0
  173. package/src/shared/ui/atoms/skeleton/skeleton.types.ts +9 -0
  174. package/src/shared/ui/atoms/spinner/index.ts +2 -0
  175. package/src/shared/ui/atoms/spinner/spinner.styles.ts +102 -0
  176. package/src/shared/ui/atoms/spinner/spinner.tsx +48 -0
  177. package/src/shared/ui/atoms/spinner/spinner.types.ts +25 -0
  178. package/src/shared/ui/atoms/text/index.ts +2 -0
  179. package/src/shared/ui/atoms/text/text.styles.ts +186 -0
  180. package/src/shared/ui/atoms/text/text.tsx +37 -0
  181. package/src/shared/ui/atoms/text/text.types.ts +35 -0
  182. package/src/shared/ui/atoms/touch/components/haptics/haptics.styles.ts +21 -0
  183. package/src/shared/ui/atoms/touch/components/haptics/haptics.tsx +28 -0
  184. package/src/shared/ui/atoms/touch/components/haptics/haptics.types.ts +17 -0
  185. package/src/shared/ui/atoms/touch/components/haptics/index.ts +2 -0
  186. package/src/shared/ui/atoms/touch/components/index.ts +3 -0
  187. package/src/shared/ui/atoms/touch/components/ripple/index.ts +2 -0
  188. package/src/shared/ui/atoms/touch/components/ripple/ripple.styles.ts +78 -0
  189. package/src/shared/ui/atoms/touch/components/ripple/ripple.tsx +29 -0
  190. package/src/shared/ui/atoms/touch/components/ripple/ripple.types.ts +17 -0
  191. package/src/shared/ui/atoms/touch/components/spring/index.ts +2 -0
  192. package/src/shared/ui/atoms/touch/components/spring/spring.styles.ts +31 -0
  193. package/src/shared/ui/atoms/touch/components/spring/spring.tsx +28 -0
  194. package/src/shared/ui/atoms/touch/components/spring/spring.types.ts +17 -0
  195. package/src/shared/ui/atoms/touch/index.ts +2 -0
  196. package/src/shared/ui/atoms/touch/touch.styles.ts +14 -0
  197. package/src/shared/ui/atoms/touch/touch.tsx +137 -0
  198. package/src/shared/ui/atoms/touch/touch.types.ts +27 -0
  199. package/src/shared/ui/atoms/visibility/index.ts +2 -0
  200. package/src/shared/ui/atoms/visibility/visibility.styles.ts +85 -0
  201. package/src/shared/ui/atoms/visibility/visibility.tsx +61 -0
  202. package/src/shared/ui/atoms/visibility/visibility.types.ts +34 -0
  203. package/src/shared/ui/molecules/keyboard-area/keyboard-area.styles.ts +11 -9
  204. package/src/shared/ui/molecules/keyboard-area/keyboard-area.tsx +3 -6
  205. package/src/shared/ui/molecules/refresh-control/refresh-control.tsx +3 -5
  206. package/src/shared/ui/molecules/refresh-control/refresh-control.types.ts +1 -1
  207. package/src/shared/ui/molecules/slider/components/indicator/components/dot/dot.styles.ts +41 -0
  208. package/src/shared/ui/molecules/slider/components/indicator/components/dot/dot.tsx +12 -0
  209. package/src/shared/ui/molecules/slider/components/indicator/components/dot/dot.types.ts +13 -0
  210. package/src/shared/ui/molecules/slider/components/indicator/components/dot/index.ts +2 -0
  211. package/src/shared/ui/molecules/slider/components/indicator/index.ts +2 -0
  212. package/src/shared/ui/molecules/slider/components/indicator/indicator.styles.ts +20 -0
  213. package/src/shared/ui/molecules/slider/components/indicator/indicator.tsx +22 -0
  214. package/src/shared/ui/molecules/slider/components/indicator/indicator.types.ts +10 -0
  215. package/src/shared/ui/molecules/slider/index.ts +3 -0
  216. package/src/shared/ui/molecules/slider/slider.styles.ts +68 -0
  217. package/src/shared/ui/molecules/slider/slider.tsx +64 -0
  218. package/src/shared/ui/molecules/slider/slider.types.ts +28 -0
  219. package/src/shared/ui/organisms/bar/bar.styles.ts +100 -0
  220. package/src/shared/ui/organisms/bar/bar.tsx +89 -0
  221. package/src/shared/ui/organisms/bar/bar.types.ts +49 -0
  222. package/src/shared/ui/organisms/bar/index.ts +2 -0
  223. package/src/shared/ui/organisms/bar-tab/bar-tab.tsx +9 -0
  224. package/src/shared/ui/organisms/bar-tab/bar-tab.types.ts +5 -0
  225. package/src/shared/ui/organisms/bar-tab/components/index.ts +1 -0
  226. package/src/shared/ui/organisms/bar-tab/components/tab/index.ts +2 -0
  227. package/src/shared/ui/organisms/bar-tab/components/tab/tab.styles.ts +21 -0
  228. package/src/shared/ui/organisms/bar-tab/components/tab/tab.tsx +18 -0
  229. package/src/shared/ui/organisms/bar-tab/components/tab/tab.types.ts +5 -0
  230. package/src/shared/ui/organisms/bar-tab/index.ts +2 -0
  231. package/src/shared/ui/organisms/bar-tab-navigation/bar-tab-navigation.styles.ts +22 -0
  232. package/src/shared/ui/organisms/bar-tab-navigation/bar-tab-navigation.tsx +66 -0
  233. package/src/shared/ui/organisms/bar-tab-navigation/bar-tab-navigation.types.ts +5 -0
  234. package/src/shared/ui/organisms/bar-tab-navigation/components/index.ts +1 -0
  235. package/src/shared/ui/organisms/bar-tab-navigation/components/tab-navigation/index.ts +2 -0
  236. package/src/shared/ui/organisms/bar-tab-navigation/components/tab-navigation/tab-navigation.styles.ts +56 -0
  237. package/src/shared/ui/organisms/bar-tab-navigation/components/tab-navigation/tab-navigation.tsx +30 -0
  238. package/src/shared/ui/organisms/bar-tab-navigation/components/tab-navigation/tab-navigation.types.ts +7 -0
  239. package/src/shared/ui/organisms/bar-tab-navigation/index.ts +2 -0
  240. package/src/shared/ui/organisms/index.ts +4 -1
  241. package/src/shared/ui/organisms/slider/components/indicator/components/dot/dot.styles.ts +41 -0
  242. package/src/shared/ui/organisms/slider/components/indicator/components/dot/dot.tsx +12 -0
  243. package/src/shared/ui/organisms/slider/components/indicator/components/dot/dot.types.ts +13 -0
  244. package/src/shared/ui/organisms/slider/components/indicator/components/dot/index.ts +2 -0
  245. package/src/shared/ui/organisms/slider/components/indicator/index.ts +2 -0
  246. package/src/shared/ui/organisms/slider/components/indicator/indicator.styles.ts +20 -0
  247. package/src/shared/ui/organisms/slider/components/indicator/indicator.tsx +22 -0
  248. package/src/shared/ui/organisms/slider/components/indicator/indicator.types.ts +10 -0
  249. package/src/shared/ui/organisms/slider/index.ts +3 -0
  250. package/src/shared/ui/organisms/slider/slider.styles.ts +68 -0
  251. package/src/shared/ui/organisms/slider/slider.tsx +64 -0
  252. package/src/shared/ui/organisms/slider/slider.types.ts +28 -0
  253. package/src/shared/ui/templates/index.ts +3 -0
  254. package/src/shared/ui/templates/modal-container/index.ts +13 -0
  255. package/src/shared/ui/templates/modal-container/modal-container-list.tsx +45 -0
  256. package/src/shared/ui/templates/modal-container/modal-container-scroll.tsx +66 -0
  257. package/src/shared/ui/templates/modal-container/modal-container-section-list.tsx +46 -0
  258. package/src/shared/ui/templates/modal-container/modal-container.hooks.tsx +172 -0
  259. package/src/shared/ui/templates/modal-container/modal-container.styles.ts +121 -0
  260. package/src/shared/ui/templates/modal-container/modal-container.types.ts +69 -0
  261. package/src/shared/ui/templates/screen-container/index.ts +1 -1
  262. package/src/shared/ui/templates/screen-container/screen-container-list.tsx +28 -10
  263. package/src/shared/ui/templates/screen-container/screen-container-scroll.tsx +28 -10
  264. package/src/shared/ui/templates/screen-container/screen-container-section-list.tsx +29 -11
  265. package/src/shared/ui/templates/screen-container/screen-container.hooks.tsx +79 -8
  266. package/src/shared/ui/templates/screen-container/screen-container.styles.ts +105 -15
  267. package/src/shared/ui/templates/screen-container/screen-container.types.tsx +34 -7
  268. package/src/shared/ui/templates/screen-header/components/index.ts +6 -0
  269. package/src/shared/ui/templates/screen-header/components/screen-header-description/index.ts +2 -0
  270. package/src/shared/ui/templates/screen-header/components/screen-header-description/screen-header-description.tsx +15 -0
  271. package/src/shared/ui/templates/screen-header/components/screen-header-description/screen-header-description.types.ts +11 -0
  272. package/src/shared/ui/templates/screen-header/components/screen-header-icon/index.ts +2 -0
  273. package/src/shared/ui/templates/screen-header/components/screen-header-icon/screen-header-icon.styles.ts +44 -0
  274. package/src/shared/ui/templates/screen-header/components/screen-header-icon/screen-header-icon.tsx +65 -0
  275. package/src/shared/ui/templates/screen-header/components/screen-header-icon/screen-header-icon.types.ts +14 -0
  276. package/src/shared/ui/templates/screen-header/components/screen-header-icon-back/index.ts +2 -0
  277. package/src/shared/ui/templates/screen-header/components/screen-header-icon-back/screen-header-icon-back.tsx +17 -0
  278. package/src/shared/ui/templates/screen-header/components/screen-header-icon-back/screen-header-icon-back.types.ts +6 -0
  279. package/src/shared/ui/templates/screen-header/components/screen-header-icon-close/index.ts +2 -0
  280. package/src/shared/ui/templates/screen-header/components/screen-header-icon-close/screen-header-icon-close.tsx +27 -0
  281. package/src/shared/ui/templates/screen-header/components/screen-header-icon-close/screen-header-icon-close.types.ts +10 -0
  282. package/src/shared/ui/templates/screen-header/components/screen-header-info/index.ts +2 -0
  283. package/src/shared/ui/templates/screen-header/components/screen-header-info/screen-header-info.tsx +15 -0
  284. package/src/shared/ui/templates/screen-header/components/screen-header-info/screen-header-info.types.ts +10 -0
  285. package/src/shared/ui/templates/screen-header/components/screen-header-title/index.ts +2 -0
  286. package/src/shared/ui/templates/screen-header/components/screen-header-title/screen-header-title.tsx +19 -0
  287. package/src/shared/ui/templates/screen-header/components/screen-header-title/screen-header-title.types.ts +13 -0
  288. package/src/shared/ui/templates/screen-header/index.ts +3 -0
  289. package/src/shared/ui/templates/screen-header/screen-header.styles.ts +49 -0
  290. package/src/shared/ui/templates/screen-header/screen-header.tsx +26 -0
  291. package/src/shared/ui/templates/screen-header/screen-header.types.ts +15 -0
  292. package/src/shared/ui/templates/web-container/index.ts +2 -0
  293. package/src/shared/ui/templates/web-container/web-container.styles.ts +34 -0
  294. package/src/shared/ui/templates/web-container/web-container.tsx +172 -0
  295. package/src/shared/ui/templates/web-container/web-container.types.ts +21 -0
  296. package/.claude/rules/app-routing.mdc +0 -47
  297. package/.claude/rules/exports-at-end.mdc +0 -55
  298. package/.claude/rules/kebab-case-naming.mdc +0 -29
  299. package/.claude/rules/mediacubeco-packages.mdc +0 -56
  300. package/.claude/skills/generate-api-model/SKILL.md +0 -230
  301. package/.claude/skills/generate-api-model/references/resources/common.ts +0 -8
  302. package/.claude/skills/generate-api-model-mock/SKILL.md +0 -56
  303. package/.claude/skills/git-commit/SKILL.md +0 -139
  304. package/.gitignore +0 -34
  305. package/src/shared/assets/icons/like.tsx +0 -17
  306. package/src/shared/hooks/use-animated.ts +0 -200
  307. package/src/shared/hooks/use-mixins.ts +0 -36
  308. package/src/shared/hooks/use-safe-area.ts +0 -75
  309. package/src/shared/lib/api/repositories/auth/auth.ts +0 -23
  310. package/src/shared/lib/api/repositories/auth/auth.types.ts +0 -22
  311. package/src/shared/lib/api/repositories/auth/index.ts +0 -1
  312. package/src/shared/lib/navigation/hooks/use-navigation-native-tabs.ts +0 -10
  313. package/src/shared/lib/navigation/hooks/use-navigation-options.ts +0 -123
  314. package/src/shared/lib/navigation/navigation-native-tabs.context.tsx +0 -5
  315. package/src/shared/lib/navigation/navigation-native-tabs.provider.tsx +0 -12
  316. package/src/shared/lib/theme/constants/borders.ts +0 -8
  317. package/src/shared/lib/theme/constants/weights.ts +0 -13
  318. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/index.ts +0 -0
  319. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/post/index.ts +0 -0
  320. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/post/post-comment.ts +0 -0
  321. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/post/post.ts +0 -0
  322. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/user/index.ts +0 -0
  323. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/user/user-settings.ts +0 -0
  324. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/user/user-verification.ts +0 -0
  325. /package/.claude/skills/{generate-api-model/references → api/references/model}/entities/user/user.ts +0 -0
  326. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/index.ts +0 -0
  327. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/post/index.ts +0 -0
  328. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/post/post-comment.ts +0 -0
  329. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/post/post.ts +0 -0
  330. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/user/index.ts +0 -0
  331. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/user/user-settings.ts +0 -0
  332. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/user/user-verification.ts +0 -0
  333. /package/.claude/skills/{generate-api-model/references → api/references/model}/resources/user/user.ts +0 -0
@@ -0,0 +1,172 @@
1
+ import { type IterableOf, type NotNullable } from '@mediacubeco/base/types'
2
+ import { runCallback } from '@mediacubeco/base/utils'
3
+ import { useCallback, useState } from 'react'
4
+ import { View } from 'react-native'
5
+ import { WebView, type WebViewNavigation, type WebViewProps } from 'react-native-webview'
6
+ import { useComposeRef } from '../../../hooks'
7
+ import { Share } from '../../../services'
8
+ import { Spinner } from '../../atoms'
9
+ import { ScreenContainerScroll } from '../screen-container'
10
+ import {
11
+ ScreenHeader,
12
+ ScreenHeaderIcon,
13
+ ScreenHeaderIconClose,
14
+ ScreenHeaderInfo,
15
+ } from '../screen-header'
16
+ import { useWebContainerStyles } from './web-container.styles'
17
+ import { type WebContainerProps } from './web-container.types'
18
+
19
+ const iconList = ['share' as const, 'refresh' as const]
20
+ const originWhitelist = ['*']
21
+ const injectedJavaScript =
22
+ 'window.ReactNativeWebView.postMessage(JSON.stringify(window.location.hostname))'
23
+
24
+ /**
25
+ * Корневой контейнер WebView для модального окна (formSheet на всю высоту). Рисует шапку
26
+ * с заголовком текущей страницы и кнопкой закрытия, следит за жизненным циклом загрузки:
27
+ * пока страница грузится — оверлей со спиннером, при провале навигации — оверлей ошибки.
28
+ * Все нативные пропсы `WebView` пробрасываются насквозь; свои колбэки жизненного цикла
29
+ * контейнер оборачивает и вызывает пользовательские после своих.
30
+ */
31
+ const WebContainer = ({
32
+ ref: initRef,
33
+ uri,
34
+ method,
35
+ headers,
36
+ body,
37
+ title: initTitle = '',
38
+ onChange,
39
+ }: WebContainerProps) => {
40
+ const hasURI = !!uri
41
+
42
+ const [title, setTitle] = useState(initTitle)
43
+ const [description, setDescription] = useState('')
44
+ const [currentUrl, setCurrentUrl] = useState(uri ?? '')
45
+ const [_errorCode, setErrorCode] = useState('')
46
+ const [_errorDescription, setErrorDescription] = useState('')
47
+ const [didFail, setDidFail] = useState(false)
48
+ const [isPending, setIsPending] = useState(true)
49
+ const ref = useComposeRef<WebView>(initRef)
50
+ const { styles } = useWebContainerStyles()
51
+
52
+ const shouldPlaceholder = !hasURI || didFail
53
+ const shouldSpinner = hasURI && isPending
54
+
55
+ const handleReload = useCallback(() => {
56
+ runCallback(ref.current?.reload)
57
+ }, [ref])
58
+
59
+ const handleHeaderIconPress = useCallback(
60
+ async (value: IterableOf<typeof iconList>) => {
61
+ if (value === 'refresh') {
62
+ handleReload()
63
+ } else if (value === 'share' && currentUrl) {
64
+ await Share.openUrl(currentUrl)
65
+ }
66
+ },
67
+ [currentUrl, handleReload]
68
+ )
69
+
70
+ const handleLoadStart: NotNullable<WebViewProps['onLoadStart']> = useCallback(() => {
71
+ setDidFail(false)
72
+ }, [])
73
+
74
+ const handleLoadEnd: NotNullable<WebViewProps['onLoadEnd']> = useCallback(() => {
75
+ setIsPending(false)
76
+ }, [])
77
+
78
+ const handleError: NotNullable<WebViewProps['onError']> = useCallback((event) => {
79
+ const { code, description } = event.nativeEvent
80
+
81
+ setErrorCode(String(code))
82
+ setErrorDescription(description)
83
+
84
+ setDidFail(true)
85
+ setIsPending(false)
86
+ }, [])
87
+
88
+ const handleHttpError: NotNullable<WebViewProps['onHttpError']> = useCallback((event) => {
89
+ const { statusCode, description } = event.nativeEvent
90
+
91
+ setErrorCode(String(statusCode))
92
+ setErrorDescription(description)
93
+
94
+ setDidFail(true)
95
+ setIsPending(false)
96
+ }, [])
97
+
98
+ const handleNavigationStateChange = useCallback(
99
+ (event: WebViewNavigation) => {
100
+ const info = event.title.split('|')
101
+
102
+ const title = info[0]?.trim()
103
+ const description = info[1]?.trim()
104
+
105
+ if (title) {
106
+ setTitle(title)
107
+ }
108
+
109
+ if (description) {
110
+ setDescription(description)
111
+ }
112
+
113
+ if (event.url) {
114
+ setCurrentUrl(event.url)
115
+ }
116
+
117
+ runCallback(onChange, event)
118
+ },
119
+ [onChange]
120
+ )
121
+
122
+ return (
123
+ <ScreenContainerScroll
124
+ variant={'secondary'}
125
+ wrapperStyle={styles.wrapper}
126
+ outerStyle={styles.outer}
127
+ innerStyle={styles.inner}
128
+ withScroll={isPending || didFail}
129
+ withAreaTop={false}
130
+ withAreaBottom={false}
131
+ withIndentBottom={false}
132
+ screenHeader={
133
+ <ScreenHeader
134
+ left={<ScreenHeaderIconClose />}
135
+ center={<ScreenHeaderInfo title={title} description={description} />}
136
+ right={<ScreenHeaderIcon value={iconList} onPress={handleHeaderIconPress} />}
137
+ withArea={false}
138
+ />
139
+ }
140
+ >
141
+ {hasURI && (
142
+ <WebView
143
+ ref={ref}
144
+ style={styles.web}
145
+ source={{ uri, method, headers, body }}
146
+ androidLayerType={'hardware'}
147
+ originWhitelist={originWhitelist}
148
+ injectedJavaScript={injectedJavaScript}
149
+ pullToRefreshEnabled={!isPending}
150
+ scalesPageToFit={false}
151
+ sharedCookiesEnabled={true}
152
+ allowsInlineMediaPlayback={true}
153
+ showsVerticalScrollIndicator={false}
154
+ mediaPlaybackRequiresUserAction={false}
155
+ onLoadStart={handleLoadStart}
156
+ onLoadEnd={handleLoadEnd}
157
+ onError={handleError}
158
+ onHttpError={handleHttpError}
159
+ onNavigationStateChange={handleNavigationStateChange}
160
+ />
161
+ )}
162
+ {shouldPlaceholder && <></>}
163
+ {shouldSpinner && (
164
+ <View style={styles.spinner}>
165
+ <Spinner />
166
+ </View>
167
+ )}
168
+ </ScreenContainerScroll>
169
+ )
170
+ }
171
+
172
+ export default WebContainer
@@ -0,0 +1,21 @@
1
+ import { type RefObject } from 'react'
2
+ import { type WebView, type WebViewProps } from 'react-native-webview'
3
+
4
+ /**
5
+ * Пропсы корневого контейнера WebView: обёртка над нативными пропсами `WebView`
6
+ * с шапкой (заголовок текущей страницы и закрытие), индикатором загрузки и
7
+ * состоянием ошибки.
8
+ */
9
+ type WebContainerProps = {
10
+ ref?: RefObject<WebView>
11
+ uri?: string
12
+ method?: string
13
+ headers?: object
14
+ body?: string
15
+ /** Заголовок шапки, пока страница не сообщила собственный title. */
16
+ title?: string
17
+ /** Закрытие модального окна кнопкой в шапке. */
18
+ onChange?: WebViewProps['onNavigationStateChange']
19
+ }
20
+
21
+ export type { WebContainerProps }
@@ -1,47 +0,0 @@
1
- ---
2
- description: Thin Expo Router layer in src/app — layout/screen and delegation to ~pages
3
- globs: src/app/**/*.tsx
4
- alwaysApply: false
5
- ---
6
-
7
- # `src/app` layer (Expo Router)
8
-
9
- Files under `src/app` only wire routes to implementation. Screen UI and business logic live in `~pages/*` (or other features), not in `app`.
10
-
11
- ## `_layout.tsx`
12
-
13
- - The route’s main component is a function named **`layout`** (`Stack` / `Tabs` / `NativeTabs` config, `Stack.Screen`, options).
14
- - **Default**-export that function (Expo Router requirement). Follow the “exports at end” policy in `.cursor/rules/exports-at-end.mdc`: declare `function layout()` first, then `export default layout` at the bottom of the file.
15
- - Do not turn `_layout` into a “screen”: no content markup, only navigation and options.
16
-
17
- ## Route screen files (`index.tsx`, `[param].tsx`, named routes, etc.)
18
-
19
- - The main component is a function named **`screen`**; it only renders the root screen from `~pages/...` (import a single root screen component).
20
- - **Default**-export it (`export default screen` at the end of the file, same export rules).
21
- - Do not duplicate screen markup in the route file — only a thin wrapper around the `~pages` import.
22
-
23
- ## Exceptions
24
-
25
- - Special Expo Router files (`+not-found.tsx`, `+html.tsx`, etc.), if you add them, may follow a different contract — use Expo’s docs for that file.
26
-
27
- ## Templates
28
-
29
- ```tsx
30
- // _layout.tsx — navigation only
31
- function Layout() {
32
- return <Stack>{/* Stack.Screen … */}</Stack>
33
- }
34
-
35
- export default Layout
36
- ```
37
-
38
- ```tsx
39
- // route screen
40
- import { SomeFeatureScreen } from '~pages/some-feature'
41
-
42
- function Screen() {
43
- return <SomeFeatureScreen />
44
- }
45
-
46
- export default Screen
47
- ```
@@ -1,55 +0,0 @@
1
- ---
2
- description: Place all export statements at the end of TS/TSX modules
3
- globs: **/*.{ts,tsx}
4
- alwaysApply: false
5
- ---
6
-
7
- # Exports at end of file
8
-
9
- All public exports from a module must appear **at the end of the file**, after imports, types, and implementation.
10
-
11
- ## Rules
12
-
13
- - Do not scatter `export` on declarations through the file (e.g. `export const`, `export function`, `export class`, `export interface`). Declare first, then export in one place at the bottom.
14
- - Use explicit export statements: `export { … }`, `export type { … }`, and `export default …`.
15
- - Barrel files (`export … from '…'`) should also keep exports in the final section of the file when combined with other code (prefer dedicated barrel files with only re-exports).
16
-
17
- ## Suggested order (bottom of file)
18
-
19
- 1. `export { … }` — runtime named exports
20
- 2. `export type { … }` — type-only exports
21
- 3. `export default …` — default export last
22
-
23
- Adjust if the team prefers default first; stay consistent within the repo.
24
-
25
- ## Examples
26
-
27
- ```typescript
28
- // ❌ BAD — exports mixed with implementation
29
- export const someVar = 1
30
- export type { SomeType }
31
- export function someFunction() {}
32
-
33
- // ✅ GOOD — definitions first, exports last
34
- const someVar = 1
35
- type SomeType = { x: number }
36
- function someFunction() {}
37
-
38
- export { someVar, someFunction }
39
- export type { SomeType }
40
- export default someFunction
41
- ```
42
-
43
- ```typescript
44
- // ❌ BAD
45
- export default function SomeComponent() {
46
- return null
47
- }
48
-
49
- // ✅ GOOD
50
- function SomeComponent() {
51
- return null
52
- }
53
-
54
- export default SomeComponent
55
- ```
@@ -1,29 +0,0 @@
1
- ---
2
- description: Enforce kebab-case naming for all files and folders
3
- alwaysApply: true
4
- ---
5
-
6
- # Kebab-case naming convention
7
-
8
- All files and folders must use kebab-case naming.
9
-
10
- ## Rules
11
-
12
- - Use only lowercase letters, digits, and hyphens: `some-name.ts`
13
- - No camelCase, PascalCase, or snake_case in file/folder names
14
- - Dots are allowed only for file extensions and config modifiers: `eslint.config.js`, `app.json`
15
-
16
- ## Examples
17
-
18
- ```
19
- # ✅ GOOD
20
- src/shared/ui/
21
- some-entity
22
- some-feature
23
- some-widget
24
-
25
- # ❌ BAD
26
- SomeEntity
27
- some_feature
28
- someWidget
29
- ```
@@ -1,56 +0,0 @@
1
- ---
2
- description: Enforce use of @mediacubeco/* corporate packages over custom re-implementations
3
- alwaysApply: true
4
- ---
5
-
6
- # Use @mediacubeco/\* corporate packages
7
-
8
- All utilities, helpers, hooks, and configs that exist in `@mediacubeco/*` packages **must** be imported from there. Do not duplicate or re-implement what is already provided.
9
-
10
- ## Available packages
11
-
12
- To discover what each package exports, read its DTS index:
13
-
14
- - `@mediacubeco/base` — `dist/index.d.ts`
15
- - subpaths: `/helpers`, `/services`, `/types`, `/utils`
16
- - `@mediacubeco/base-react-native` — `dist/index.d.ts`
17
- - subpaths: `/helpers`, `/hooks`, `/utils`
18
-
19
- ## Rules
20
-
21
- - Before writing any utility, helper, hook, or type — read the relevant package's DTS index and check if it already exists.
22
- - Always import via subpath, never from the package root:
23
- - `@mediacubeco/base/utils` ✅ — `@mediacubeco/base` ❌
24
- - `@mediacubeco/base-react-native/hooks` ✅ — `@mediacubeco/base-react-native` ❌
25
- - Never copy source from a `@mediacubeco/*` package into the app.
26
- - ESLint, Prettier, and TypeScript configs must extend the corresponding `@mediacubeco/*` config package — do not inline equivalent rules.
27
- - If something is missing from a `@mediacubeco/*` package, add it there first, then import it in the app.
28
-
29
- ## Examples
30
-
31
- ```typescript
32
- // ✅ GOOD — subpath import
33
- import { isNull } from '@mediacubeco/base/utils'
34
-
35
- // ❌ BAD — inline
36
- value === null
37
-
38
- // ❌ BAD — root import
39
- import { isNull } from '@mediacubeco/base'
40
-
41
- // ❌ BAD — reimplementing what already exists
42
- function isNull(value: unknown): value is null {
43
- return value === null
44
- }
45
- ```
46
-
47
- ```typescript
48
- // ✅ GOOD — subpath import
49
- import { useKeyboard } from '@mediacubeco/base-react-native/hooks'
50
-
51
- // ❌ BAD — root import
52
- import { useKeyboard } from '@mediacubeco/base-react-native'
53
-
54
- // ❌ BAD — custom re-implementation
55
- function useKeyboard() { /* ... */ }
56
- ```
@@ -1,230 +0,0 @@
1
- ---
2
- name: generate-api-model
3
- description: >-
4
- Generates API Resource types and Entity classes from a backend JSON response.
5
- Use this skill whenever the user provides a backend JSON object or API schema
6
- and wants TypeScript types generated from it, asks to "add a new API model",
7
- "create an entity for...", "generate resource and entity", or wants to model
8
- an API response. Also use when adding new domain types to the shared API
9
- library (resources/ + entities/ folders).
10
- ---
11
-
12
- # Generate API Model
13
-
14
- ## What this skill does
15
-
16
- Take a **backend JSON response** (or API contract) and produce two TypeScript artifacts per domain object:
17
-
18
- 1. **Resource** (`*Resource`) — a `type` that mirrors the **exact wire format** of the backend: field names are copied verbatim, including any snake_case, camelCase, kebab-case, UPPER_SNAKE_CASE, or PascalCase the backend uses.
19
- 2. **Entity** (`*Entity`) — a `class` that maps every field to strict **camelCase** and applies project naming conventions for dates, arrays, and booleans.
20
-
21
- ## Filesystem layout
22
-
23
- ```
24
- <api-lib>/
25
- ├── resources/
26
- │ ├── common.ts ← BaseResource shared type (see references/)
27
- │ ├── index.ts ← barrel re-exporting all domains
28
- │ └── <domain>/
29
- │ ├── index.ts ← barrel for this domain
30
- │ └── <domain>.ts ← Resource type(s) for this domain
31
- └── entities/
32
- ├── common.ts ← BaseEntity<T> base class (see references/)
33
- ├── index.ts ← barrel re-exporting all domains
34
- └── <domain>/
35
- ├── index.ts ← barrel for this domain
36
- └── <domain>.ts ← Entity class for this domain
37
- ```
38
-
39
- Domain folder names are **kebab-case**. See `references/` for complete working examples.
40
-
41
- ---
42
-
43
- ## Step 1 — Identify domains
44
-
45
- From the backend JSON, identify independent domain objects. Exclude generic HTTP envelopes (pagination wrappers, status/error shapes) unless the user explicitly requests them.
46
-
47
- **If the user did not specify a domain name for the root object — ask before generating anything.** Never invent a domain name on your own. The root domain name determines all type names, filenames, and folder names, so it must be confirmed by the user.
48
-
49
- Every distinct nested object that carries its own data becomes its own `*Resource` + `*Entity` pair.
50
-
51
- **Where to place nested domain files:** if a nested object only appears inside one parent domain, put its files **in the parent's folder** (e.g., `brand/brand-translation.ts`, `post/post-comment.ts`, `user/user-settings.ts`). Create a separate top-level folder only when the object appears across multiple domains or is clearly a standalone concept (e.g., `stored-file` that could be attached to many entities).
52
-
53
- ---
54
-
55
- ## Step 2 — Resource types (wire format)
56
-
57
- **Rule: Resource field names must exactly match the backend.** Copy them verbatim — do not normalize, rename, or change casing.
58
-
59
- ```typescript
60
- // Backend sends: { "first_name": "John", "UserAge": 30, "is-active": true }
61
- type UserResource = BaseResource & {
62
- 'first_name'?: string // snake_case preserved as-is
63
- 'UserAge'?: number // PascalCase preserved as-is
64
- 'is-active'?: boolean // hyphenated keys must be quoted
65
- }
66
- ```
67
-
68
- Additional rules:
69
-
70
- - All fields are **optional** (`?`) by default, unless the contract guarantees the field is always present.
71
- - **Do not add `id`, `createdAt` / `updatedAt`, or `isPending`** to domain Resource types — these are already declared in `BaseResource` and inherited automatically.
72
- - Nested objects → their own `*Resource` type in a sibling file, referenced here.
73
- - Arrays of objects → `ChildResource[]`.
74
- - String enums → `export enum` in the same file as the resource that owns the field.
75
- - Import `BaseResource` from `../common` (or the resources barrel).
76
-
77
- ---
78
-
79
- ## Step 3 — Entity classes (always camelCase)
80
-
81
- Every property in the Entity must be **camelCase**, regardless of the wire-format key.
82
-
83
- ### Case conversion table
84
-
85
- | Wire format | Wire key example | Entity field |
86
- | ---------------- | ----------------- | --------------- |
87
- | snake_case | `created_at` | `createdAt` |
88
- | snake_case | `first_name` | `firstName` |
89
- | snake_case | `number_of_likes` | `numberOfLikes` |
90
- | kebab-case | `user-name` | `userName` |
91
- | kebab-case | `post-id` | `postId` |
92
- | UPPER_SNAKE_CASE | `USER_NAME` | `userName` |
93
- | UPPER_SNAKE_CASE | `POST_ID` | `postId` |
94
- | camelCase | `firstName` | `firstName` |
95
- | PascalCase | `FirstName` | `firstName` |
96
-
97
- **Algorithm:** split the wire key on `_`, `-`, spaces, or case-boundary transitions (uppercase after lowercase) → lowercase the first segment, capitalize the first letter of every subsequent segment → join.
98
-
99
- ### Entity naming conventions
100
-
101
- After converting to camelCase, apply these semantic rules:
102
-
103
- #### Dates → must end in `at`
104
-
105
- Any field that represents a point in time must end with `at`.
106
-
107
- ```
108
- created_at → createdAt ✓
109
- updated_at → updatedAt ✓
110
- publish_date → publishedAt ✓ (rename: "date" → "at")
111
- expiry → expiredAt ✓ (rename: add "at" suffix)
112
- birth_date → birthAt ✓
113
- ```
114
-
115
- #### Arrays → must end in `list`
116
-
117
- All array properties in Entity end in `list`. Strip a trailing plural `s` (when it makes the base form a clean word) before appending `List`.
118
-
119
- Resource keeps the backend wire name; Entity renames to `*List`.
120
-
121
- ```
122
- // Resource field (wire name) Entity field (camelCase + list)
123
- comments: PostCommentResource[] → commentList: PostCommentEntity[]
124
- tags: string[] → tagList: string[]
125
- user_posts: PostResource[] → userPostList: PostEntity[]
126
- items: ItemResource[] → itemList: ItemEntity[]
127
- ```
128
-
129
- If the backend already uses a `list`-style name (e.g., `comment_list`), the Entity field is simply the camelCase conversion: `commentList`.
130
-
131
- #### Booleans → should start with `is`, `has`, `did`, `can`, `should`, `was`, `will`
132
-
133
- ```
134
- is_email_verified → isEmailVerified ✓
135
- verified → isVerified ✓ (add prefix when the boolean nature is clear)
136
- email_confirmed → didConfirmEmail ✓
137
- can_edit → canEdit ✓
138
- has_access → hasAccess ✓
139
- ```
140
-
141
- ### Entity constructor pattern
142
-
143
- **Do not re-declare or set `id`, `createdAt`, `updatedAt` in domain entities** — `BaseEntity` already handles them via `super(resource, context)`. Only add fields that are specific to this domain.
144
-
145
- See `references/entities/common.ts` for the full `BaseEntity<T>` implementation and `references/entities/post/post.ts` for a complete domain example (with nested entity, array `→ List`, and cross-domain reference).
146
-
147
- Default values by type:
148
- | Type | Default |
149
- |------------------|-----------------------|
150
- | `string` | `''` |
151
- | `number` | `0` |
152
- | `boolean` | `false` |
153
- | `Date` | `new Date()` |
154
- | nested Entity | `new ChildEntity(resource?.field, this)` |
155
- | array | `[]` |
156
-
157
- ---
158
-
159
- ## Step 4 — Barrel index files
160
-
161
- Each `<domain>/` folder must have an `index.ts` re-exporting its modules. After adding a new domain, update the parent barrels too.
162
-
163
- See `references/resources/post/index.ts`, `references/entities/post/index.ts`, and `references/resources/index.ts` for examples.
164
-
165
- ---
166
-
167
- ## Import conventions
168
-
169
- ```typescript
170
- // Inside a Resource file:
171
- import { BaseResource } from '../common'
172
- import { ChildResource } from './child-domain'
173
-
174
- // Inside an Entity file:
175
- import { BaseResource, DomainResource } from '../../resources'
176
- import { BaseEntity } from '../common'
177
- import { ChildEntity } from '../child-domain'
178
- ```
179
-
180
- Dependency direction is **entities → resources only**. Resources never import from entities.
181
-
182
- ---
183
-
184
- ## Export style
185
-
186
- ```typescript
187
- // Resource files:
188
- export type { DomainResource }
189
- export { DomainStatusEnum } // enums use a regular (value) export
190
-
191
- // Entity files:
192
- export { DomainEntity }
193
-
194
- // Index files:
195
- export * from './domain'
196
- ```
197
-
198
- ---
199
-
200
- ## Checklist before finishing
201
-
202
- - [ ] Every Resource field name matches the backend wire format exactly (no renaming)
203
- - [ ] Every Entity property is camelCase
204
- - [ ] All date fields in Entity end in `at`
205
- - [ ] All array fields in Entity end in `list`
206
- - [ ] All boolean fields in Entity start with `is` / `has` / `did` / `can` / `should` / `was` / `will`
207
- - [ ] Nested objects have their own `*Resource` + `*Entity` files
208
- - [ ] Each domain folder has an `index.ts` barrel
209
- - [ ] Parent `resources/index.ts` and `entities/index.ts` updated
210
-
211
- ---
212
-
213
- ## Reference examples
214
-
215
- Read these files to understand the complete, working implementation:
216
-
217
- | File | What it shows |
218
- | -------------------------------------------- | ----------------------------------------------------------------------------- |
219
- | `references/resources/common.ts` | `BaseResource` type — `id`, `created_at`, `updated_at`, `is_pending` |
220
- | `references/entities/common.ts` | `BaseEntity<T>` — `generateIdFactory`, `isPending` getter, `super()` contract |
221
- | `references/resources/post/post.ts` | Resource with snake_case fields, nested types, cross-domain ref |
222
- | `references/entities/post/post.ts` | Entity with camelCase, `commentList`, `numberOfLikes`, nested `UserEntity` |
223
- | `references/resources/post/post-comment.ts` | Minimal nested Resource inside a parent domain folder |
224
- | `references/entities/post/post-comment.ts` | Minimal nested Entity inside a parent domain folder |
225
- | `references/resources/user/user.ts` | Multi-file domain Resource with two nested sub-resources |
226
- | `references/entities/user/user.ts` | Multi-file domain Entity with two nested sub-entities |
227
- | `references/resources/user/user-settings.ts` | Leaf Resource (no further nesting) |
228
- | `references/entities/user/user-settings.ts` | Leaf Entity (no further nesting) |
229
- | `references/resources/post/index.ts` | Domain barrel — re-exports all files in the folder |
230
- | `references/resources/index.ts` | Root barrel — re-exports all domains + common |
@@ -1,8 +0,0 @@
1
- type BaseResource = {
2
- id?: string
3
- created_at?: Date
4
- updated_at?: Date
5
- is_pending?: boolean
6
- }
7
-
8
- export type { BaseResource }
@@ -1,56 +0,0 @@
1
- ---
2
- name: generate-api-model-mock
3
- description: >-
4
- Generate mock data (JSON fixtures and optional helpers) aligned with API
5
- resource and entity types. Use when the user asks for mocks, mock data, test
6
- fixtures, or fake API responses.
7
- ---
8
-
9
- # Generate API model mocks
10
-
11
- ## Purpose
12
-
13
- Produce static data that **conforms** to the project’s `*Resource` types and, when useful, round-trips through `*Entity` classes the same way production code would.
14
-
15
- ## Before generating
16
-
17
- If the user has not specified **where** fixtures live or **which response shape** (single object vs array vs envelope), ask once for:
18
-
19
- - Target folder (or confirm the repo’s usual fixtures root), and
20
- - Whether the mock is raw JSON, a TS module that exports objects, or both.
21
-
22
- Do not invent a new root if the project already has a convention—search for existing `mock`, `fixtures`, or `__fixtures__` directories first.
23
-
24
- ## Alignment with the API layer
25
-
26
- Follow the same **resources / entities** split as in `generate-api-model`:
27
-
28
- 1. Read the **`{Domain}Resource`** type from `<api-lib>/resources/<domain>/<domain>.ts` (and `resources/common.ts` if the DTO extends a shared fragment).
29
- 2. Read the **`{Domain}Entity`** class from `<api-lib>/entities/<domain>/<domain>.ts` and `entities/common.ts` if you need defaults or nesting behavior.
30
- 3. Field names in JSON must match the **resource** type (wire names), not entity getter names—unless the user explicitly wants a camelCase transport sample that still type-checks via mapping.
31
-
32
- Generate **2–3** sample items unless the user asks otherwise. Values should be realistic and respect optional vs required fields implied by the types.
33
-
34
- ## Typical artifacts
35
-
36
- ### Fixture file (e.g. `resource.json` or `*.mock.json`)
37
-
38
- Valid JSON array or object matching the agreed response shape; property names match `*Resource`.
39
-
40
- ### Optional helper module (e.g. `entity.ts` or `*.ts`)
41
-
42
- - Import the resource type from the API barrel or the domain module.
43
- - Import the fixture (JSON module or inline object) according to project bundler/tsconfig rules.
44
- - Export functions such as `get{Domain}MockResource()` that return a **deep clone** (e.g. `JSON.parse(JSON.stringify(data))`) when callers must not mutate shared state.
45
- - If tests should use entities, export helpers that return `new {Domain}Entity(resource)` from the same payload.
46
-
47
- Annotate return types with the resource type or a dedicated mock alias (e.g. `{Domain}MockResource`) if the response is a subset or wrapper around the flat resource.
48
-
49
- ### Barrel
50
-
51
- If the folder has `index.ts`, re-export the helper module. Update the nearest parent barrel only if that matches existing project practice.
52
-
53
- ## Constraints
54
-
55
- - Do not drift from the **current** `*Resource` definition; if the contract changed, update the types first (see `generate-api-model`), then regenerate mocks.
56
- - Keep skills **abstract**: no hard-coded app routes, copy-pasted production payloads, or long excerpts from `src/` in this file—describe steps and placeholders, not a snapshot of one endpoint.