@mediacubeco/expo-template-fsd 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/.claude/rules/app-routing.mdc +5 -5
  2. package/.claude/rules/mediacubeco-packages.mdc +56 -0
  3. package/.claude/settings.json +11 -0
  4. package/.claude/settings.local.json +11 -0
  5. package/.claude/skills/code-style/SKILL.md +1 -0
  6. package/.claude/skills/generate-api-model/SKILL.md +193 -61
  7. package/.claude/skills/generate-api-model/references/entities/common.ts +28 -0
  8. package/.claude/skills/generate-api-model/references/entities/index.ts +4 -0
  9. package/.claude/skills/generate-api-model/references/entities/post/index.ts +2 -0
  10. package/.claude/skills/generate-api-model/references/entities/post/post-comment.ts +16 -0
  11. package/.claude/skills/generate-api-model/references/entities/post/post.ts +27 -0
  12. package/.claude/skills/generate-api-model/references/entities/user/index.ts +3 -0
  13. package/.claude/skills/generate-api-model/references/entities/user/user-settings.ts +16 -0
  14. package/.claude/skills/generate-api-model/references/entities/user/user-verification.ts +22 -0
  15. package/.claude/skills/generate-api-model/references/entities/user/user.ts +26 -0
  16. package/.claude/skills/generate-api-model/references/resources/common.ts +8 -0
  17. package/.claude/skills/generate-api-model/references/resources/index.ts +4 -0
  18. package/.claude/skills/generate-api-model/references/resources/post/index.ts +2 -0
  19. package/.claude/skills/generate-api-model/references/resources/post/post-comment.ts +8 -0
  20. package/.claude/skills/generate-api-model/references/resources/post/post.ts +14 -0
  21. package/.claude/skills/generate-api-model/references/resources/user/index.ts +3 -0
  22. package/.claude/skills/generate-api-model/references/resources/user/user-settings.ts +8 -0
  23. package/.claude/skills/generate-api-model/references/resources/user/user-verification.ts +16 -0
  24. package/.claude/skills/generate-api-model/references/resources/user/user.ts +13 -0
  25. package/.claude/skills/git-commit/SKILL.md +139 -0
  26. package/.env +0 -1
  27. package/.env.example +0 -1
  28. package/CLAUDE.md +80 -0
  29. package/env.d.ts +0 -1
  30. package/expo-env.d.ts +3 -0
  31. package/i18next.d.ts +1 -1
  32. package/package.json +44 -43
  33. package/skills-lock.json +29 -0
  34. package/src/app/_app.tsx +2 -0
  35. package/src/shared/assets/icons/like.tsx +1 -1
  36. package/src/shared/constants/environment.ts +1 -7
  37. package/src/shared/hooks/use-animated.ts +1 -1
  38. package/src/shared/hooks/use-safe-area.ts +2 -2
  39. package/src/shared/lib/api/api.provider.tsx +2 -2
  40. package/src/shared/lib/api/api.types.ts +1 -1
  41. package/src/shared/lib/api/entities/common.ts +5 -5
  42. package/src/shared/lib/api/hooks/common.ts +1 -1
  43. package/src/shared/lib/api/models/api-instance/api-instance.ts +9 -9
  44. package/src/shared/lib/api/models/api-instance/api-instance.types.ts +1 -1
  45. package/src/shared/lib/api/models/api-instance/api-instance.utils.ts +4 -4
  46. package/src/shared/lib/api/repositories/auth/auth.ts +6 -1
  47. package/src/shared/lib/api/repositories/auth/auth.types.ts +1 -1
  48. package/src/shared/lib/api/resources/common.ts +3 -3
  49. package/src/shared/lib/localization/constants/index.ts +1 -1
  50. package/src/shared/lib/localization/hooks/use-localization.ts +1 -1
  51. package/src/shared/lib/localization/localization.provider.tsx +1 -1
  52. package/src/shared/lib/localization/localization.types.ts +1 -1
  53. package/src/shared/lib/localization/utils/storage.ts +1 -1
  54. package/src/shared/lib/navigation/hooks/use-navigation-options.ts +7 -6
  55. package/src/shared/lib/navigation/navigation.provider.tsx +2 -2
  56. package/src/shared/lib/navigation/navigation.types.ts +1 -1
  57. package/src/shared/lib/theme/theme.context.ts +1 -1
  58. package/src/shared/lib/theme/theme.provider.tsx +21 -6
  59. package/src/shared/lib/theme/theme.types.ts +2 -2
  60. package/src/shared/lib/theme/utils/storage.ts +1 -1
  61. package/src/shared/ui/molecules/keyboard-area/keyboard-area.tsx +1 -1
  62. package/src/shared/ui/molecules/refresh-control/refresh-control.tsx +1 -1
  63. package/src/shared/ui/molecules/refresh-control/refresh-control.types.ts +1 -1
  64. package/src/shared/ui/templates/screen-container/screen-container-list.tsx +1 -1
  65. package/src/shared/ui/templates/screen-container/screen-container-scroll.tsx +1 -1
  66. package/src/shared/ui/templates/screen-container/screen-container-section-list.tsx +1 -1
  67. package/src/shared/ui/templates/screen-container/screen-container.hooks.tsx +3 -3
  68. package/src/shared/ui/templates/screen-container/screen-container.styles.ts +1 -1
  69. package/src/shared/ui/templates/screen-container/screen-container.types.tsx +13 -13
  70. package/svg.d.ts +1 -1
  71. package/.claude/mcp.json +0 -0
  72. package/.claude/rules/abstract-skills-agents.mdc +0 -25
  73. package/src/shared/utils/generators.ts +0 -11
  74. package/src/shared/utils/index.ts +0 -1
  75. /package/src/{screens → pages}/.gitkeep +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  LOCALIZATION_RESOURCES,
8
8
  LOCALIZATION_SUPPORTED_LOCALE_LIST,
9
9
  } from './constants'
10
- import { LocalizationProviderProps } from './localization.types'
10
+ import { type LocalizationProviderProps } from './localization.types'
11
11
 
12
12
  const LocalizationProvider = ({ children }: LocalizationProviderProps) => {
13
13
  useMemo(() => {
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren } from 'react'
1
+ import { type PropsWithChildren } from 'react'
2
2
 
3
3
  type LocalizationProviderProps = PropsWithChildren
4
4
 
@@ -1,6 +1,6 @@
1
1
  import { Storage } from '@mediacubeco/base/services'
2
2
  import * as SecureStore from 'expo-secure-store'
3
- import { LocalizationCode } from '../constants'
3
+ import { type LocalizationCode } from '../constants'
4
4
 
5
5
  const localizationStorage = new Storage({
6
6
  get: SecureStore.getItemAsync,
@@ -1,12 +1,12 @@
1
1
  import { useCallback } from 'react'
2
2
  import { Platform } from 'react-native'
3
3
  import { isGlassEffectAPIAvailable } from 'expo-glass-effect'
4
- import { StackScreenProps } from 'expo-router'
4
+ import { type StackScreenProps } from 'expo-router'
5
5
  import {
6
- NativeTabsProps,
7
- NativeTabsTriggerIconProps,
8
- NativeTabsTriggerLabelProps,
9
- NativeTabTriggerProps,
6
+ type NativeTabsProps,
7
+ type NativeTabsTriggerIconProps,
8
+ type NativeTabsTriggerLabelProps,
9
+ type NativeTabTriggerProps,
10
10
  } from 'expo-router/unstable-native-tabs'
11
11
  import { useThemeMode, useThemeSetup } from '../../theme'
12
12
 
@@ -63,7 +63,8 @@ const useNavigationTabBarOptions = () => {
63
63
  sidebarAdaptable: Platform.OS === 'ios',
64
64
  disableTransparentOnScrollEdge: Platform.OS === 'ios',
65
65
  labelVisibilityMode: 'labeled',
66
- blurEffect: (isGlassEffectAPIAvailable() && 'none') || (isThemeModeDark && 'dark') || 'light',
66
+ blurEffect:
67
+ (isGlassEffectAPIAvailable() && 'systemMaterial') || (isThemeModeDark && 'dark') || 'light',
67
68
  } satisfies NativeTabsProps
68
69
  }, [isThemeModeDark])
69
70
 
@@ -1,10 +1,10 @@
1
1
  import { GestureHandlerRootView } from 'react-native-gesture-handler'
2
2
  import { KeyboardProvider } from 'react-native-keyboard-controller'
3
3
  import { initialWindowMetrics, SafeAreaProvider } from 'react-native-safe-area-context'
4
- import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'
4
+ import { DarkTheme, DefaultTheme, ThemeProvider } from 'expo-router/react-navigation'
5
5
  import { useThemeSetup } from '../theme'
6
6
  import { NavigationLogger } from './components'
7
- import { NavigationProviderProps } from './navigation.types'
7
+ import { type NavigationProviderProps } from './navigation.types'
8
8
 
9
9
  const NavigationProvider = ({ children }: NavigationProviderProps) => {
10
10
  const { isThemeModeDark } = useThemeSetup()
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren } from 'react'
1
+ import { type PropsWithChildren } from 'react'
2
2
 
3
3
  type NavigationProviderProps = PropsWithChildren
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { createContext } from 'react'
2
- import { ThemeContextValue } from './theme.types'
2
+ import { type ThemeContextValue } from './theme.types'
3
3
 
4
4
  const ThemeContext = createContext<null | ThemeContextValue>(null)
5
5
 
@@ -1,9 +1,10 @@
1
- import { useEffect, useMemo, useRef, useState } from 'react'
2
- import { StatusBar, useColorScheme } from 'react-native'
1
+ import { Platform } from '@mediacubeco/react-native-base'
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
3
+ import { Appearance, StatusBar, useColorScheme } from 'react-native'
3
4
  import { themeStorage } from './utils'
4
5
  import { ThemeMode, ThemeModeStatusBar, ThemeModeSystem, themes } from './constants'
5
6
  import { ThemeContext } from './theme.context'
6
- import { ThemeProviderProps } from './theme.types'
7
+ import { type ThemeProviderProps } from './theme.types'
7
8
 
8
9
  const ThemeProvider = ({ children }: ThemeProviderProps) => {
9
10
  const didDefine = useRef(false)
@@ -20,29 +21,43 @@ const ThemeProvider = ({ children }: ThemeProviderProps) => {
20
21
  return themes[currentThemeMode]
21
22
  }, [currentThemeMode])
22
23
 
24
+ const updateThemeModeSystem = useCallback((themeMode: ThemeMode) => {
25
+ if (Platform.isIos) {
26
+ if (themeMode === ThemeMode.System) {
27
+ Appearance.setColorScheme('unspecified')
28
+ } else {
29
+ Appearance.setColorScheme(themeMode)
30
+ }
31
+ }
32
+ }, [])
33
+
23
34
  useEffect(() => {
24
35
  const defineThemeMode = async () => {
25
36
  const storageThemeMode = await themeStorage.mode.get()
26
37
 
27
38
  if (storageThemeMode) {
28
- setThemeMode(storageThemeMode as ThemeMode)
39
+ setThemeMode(storageThemeMode)
40
+
41
+ updateThemeModeSystem(storageThemeMode)
29
42
  }
30
43
 
31
44
  didDefine.current = true
32
45
  }
33
46
 
34
47
  defineThemeMode()
35
- }, [])
48
+ }, [updateThemeModeSystem])
36
49
 
37
50
  useEffect(() => {
38
51
  const updateThemeMode = async () => {
39
52
  if (didDefine.current) {
40
53
  await themeStorage.mode.set(themeMode)
54
+
55
+ updateThemeModeSystem(themeMode)
41
56
  }
42
57
  }
43
58
 
44
59
  updateThemeMode()
45
- }, [themeMode])
60
+ }, [themeMode, updateThemeModeSystem])
46
61
 
47
62
  useEffect(() => {
48
63
  StatusBar.setBarStyle(
@@ -1,5 +1,5 @@
1
- import { Dispatch, PropsWithChildren, SetStateAction } from 'react'
2
- import { ThemeMode, ThemeModeSystem, themes } from './constants'
1
+ import { type Dispatch, type PropsWithChildren, type SetStateAction } from 'react'
2
+ import { type ThemeMode, type ThemeModeSystem, type themes } from './constants'
3
3
 
4
4
  type Theme = (typeof themes)[ThemeModeSystem]
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { Storage } from '@mediacubeco/base/services'
2
2
  import * as SecureStore from 'expo-secure-store'
3
- import { ThemeMode } from '../constants'
3
+ import { type ThemeMode } from '../constants'
4
4
 
5
5
  const themeStorage = new Storage({
6
6
  get: SecureStore.getItemAsync,
@@ -2,7 +2,7 @@ import { View } from 'react-native'
2
2
  import { useKeyboardHandler } from 'react-native-keyboard-controller'
3
3
  import { animate } from '../../../hooks'
4
4
  import { useKeyboardAreaStyles } from './keyboard-area.styles'
5
- import { KeyboardAreaProps } from './keyboard-area.types'
5
+ import { type KeyboardAreaProps } from './keyboard-area.types'
6
6
 
7
7
  const KeyboardAnimatedArea = animate(View)
8
8
 
@@ -3,7 +3,7 @@ import { useCallback, useState } from 'react'
3
3
  import { RefreshControl as NativeRefreshControl } from 'react-native'
4
4
  import { useSafeArea } from '../../../hooks'
5
5
  import { useThemeMode } from '../../../lib'
6
- import { RefreshControlProps } from './refresh-control.types'
6
+ import { type RefreshControlProps } from './refresh-control.types'
7
7
 
8
8
  const RefreshControl = ({ withOffset = true, onRefresh, ...props }: RefreshControlProps) => {
9
9
  const [isRefreshing, setIsRefreshing] = useState(false)
@@ -1,6 +1,6 @@
1
1
  type RefreshControlProps = {
2
2
  withOffset: boolean
3
- onRefresh: () => any | Promise<any>
3
+ onRefresh: () => unknown | Promise<unknown>
4
4
  }
5
5
 
6
6
  export type { RefreshControlProps }
@@ -1,6 +1,6 @@
1
1
  import { FlatList, View } from 'react-native'
2
2
  import { useScreenContainerProps } from './screen-container.hooks'
3
- import { ScreenContainerListProps } from './screen-container.types'
3
+ import { type ScreenContainerListProps } from './screen-container.types'
4
4
 
5
5
  const ScreenContainerList = <Item,>(props: ScreenContainerListProps<Item>) => {
6
6
  const { reference, header, footer, wrapperStyle, outerStyle, innerStyle, ...flatListProps } =
@@ -1,6 +1,6 @@
1
1
  import { ScrollView, View } from 'react-native'
2
2
  import { useScreenContainerProps } from './screen-container.hooks'
3
- import { ScreenContainerScrollProps } from './screen-container.types'
3
+ import { type ScreenContainerScrollProps } from './screen-container.types'
4
4
 
5
5
  const ScreenContainerScroll = (props: ScreenContainerScrollProps) => {
6
6
  const { reference, header, footer, wrapperStyle, outerStyle, innerStyle, ...scrollViewProps } =
@@ -1,6 +1,6 @@
1
1
  import { SectionList, View } from 'react-native'
2
2
  import { useScreenContainerProps } from './screen-container.hooks'
3
- import { ScreenContainerSectionListProps } from './screen-container.types'
3
+ import { type ScreenContainerSectionListProps } from './screen-container.types'
4
4
 
5
5
  const ScreenContainerSectionList = <Item,>(props: ScreenContainerSectionListProps<Item>) => {
6
6
  const { reference, header, footer, wrapperStyle, outerStyle, innerStyle, ...sectionListProps } =
@@ -3,9 +3,9 @@ import { View } from 'react-native'
3
3
  import { KeyboardArea, RefreshControl } from '../../molecules'
4
4
  import { useScreenContainerStyles } from './screen-container.styles'
5
5
  import {
6
- ScreenContainerListProps,
7
- ScreenContainerScrollProps,
8
- ScreenContainerSectionListProps,
6
+ type ScreenContainerListProps,
7
+ type ScreenContainerScrollProps,
8
+ type ScreenContainerSectionListProps,
9
9
  } from './screen-container.types'
10
10
 
11
11
  const useScreenContainerProps = <
@@ -1,7 +1,7 @@
1
1
  import { StyleSheet } from 'react-native'
2
2
  import { useSafeArea } from '../../../hooks'
3
3
  import { useThemeMode } from '../../../lib'
4
- import { ScreenContainerStylesConfig } from './screen-container.types'
4
+ import { type ScreenContainerStylesConfig } from './screen-container.types'
5
5
 
6
6
  const useScreenContainerStyles = ({
7
7
  withOverflowTop,
@@ -1,16 +1,16 @@
1
- import { ReactNode, Ref } from 'react'
1
+ import { type ReactNode, type Ref } from 'react'
2
2
  import {
3
- FlatList,
4
- FlatListProps,
5
- ListRenderItemInfo,
6
- ScrollView,
7
- ScrollViewProps,
8
- SectionList,
9
- SectionListData,
10
- SectionListProps,
11
- SectionListRenderItemInfo,
12
- StyleProp,
13
- ViewStyle,
3
+ type FlatList,
4
+ type FlatListProps,
5
+ type ListRenderItemInfo,
6
+ type ScrollView,
7
+ type ScrollViewProps,
8
+ type SectionList,
9
+ type SectionListData,
10
+ type SectionListProps,
11
+ type SectionListRenderItemInfo,
12
+ type StyleProp,
13
+ type ViewStyle,
14
14
  } from 'react-native'
15
15
 
16
16
  type ScreenContainerExcludeExtraNativeProps<
@@ -30,7 +30,7 @@ type ScreenContainerProps<Component extends ScrollView | FlatList | SectionList>
30
30
  footer?: ReactNode
31
31
  withOverflowTop?: boolean
32
32
  withOverflowBottom?: boolean
33
- onRefresh?: () => any | Promise<any>
33
+ onRefresh?: () => unknown | Promise<unknown>
34
34
  }
35
35
 
36
36
  type ScreenContainerScrollProps = ScreenContainerExcludeExtraNativeProps<ScrollViewProps> &
package/svg.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  declare module '*.svg' {
2
2
  import type React from 'react'
3
- import type { SvgProps } from 'react-native-svg'
3
+ import { type SvgProps } from 'react-native-svg'
4
4
 
5
5
  const content: React.FC<SvgProps>
6
6
  export default content
package/.claude/mcp.json DELETED
File without changes
@@ -1,25 +0,0 @@
1
- ---
2
- description: Skills and agent instructions must stay abstract; no project-specific code examples
3
- alwaysApply: true
4
- ---
5
-
6
- # Abstract skills and agent definitions
7
-
8
- When creating or editing **Cursor skills** (e.g. under `.cursor/skills/`), **agent prompts**, or other reusable AI guidance for this repo:
9
-
10
- ## Principles
11
-
12
- - **Stay abstract**: describe *what* to do, *constraints*, and *workflow* — not *this* app’s concrete modules, paths, or identifiers.
13
- - **No examples lifted from this codebase**: do not paste snippets, file paths, component names, store keys, or API shapes from the project as the canonical “example.” That ties the skill to one implementation and goes stale quickly.
14
- - **Use placeholders** when structure must be shown: generic names (`<entity>`, `SomeFeature`, `path/to/feature`), pseudo-paths, and minimal schematic snippets that could apply in any similar project.
15
- - **Prefer references over copies**: if the agent must follow local conventions, point to an existing project rule or high-level convention (“follow the same layout as other features in the repo”) without embedding full real-file excerpts unless the user explicitly asked for documentation of existing code.
16
-
17
- ## Why
18
-
19
- Skills and agents are meant to **transfer and stay maintainable**. Project-specific examples read as documentation of one snapshot of the repo, not as durable instructions.
20
-
21
- ## Anti-patterns
22
-
23
- - Long blocks copied from `src/...` files into a `SKILL.md`.
24
- - Hard-coded real route names, translation keys, or mock data from this app in a skill.
25
- - Teaching “how we did X” with the exact current implementation instead of the invariant rules (naming, layering, file layout conventions).
@@ -1,11 +0,0 @@
1
- const generateIdFactory = () => {
2
- let lastId = 0
3
-
4
- return (prefix: string = '') => {
5
- return `${prefix}${++lastId}`
6
- }
7
- }
8
-
9
- const generateId = generateIdFactory()
10
-
11
- export { generateIdFactory, generateId }
@@ -1 +0,0 @@
1
- export * from './generators'
File without changes