@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.
- package/.claude/rules/app-routing.mdc +5 -5
- package/.claude/rules/mediacubeco-packages.mdc +56 -0
- package/.claude/settings.json +11 -0
- package/.claude/settings.local.json +11 -0
- package/.claude/skills/code-style/SKILL.md +1 -0
- package/.claude/skills/generate-api-model/SKILL.md +193 -61
- package/.claude/skills/generate-api-model/references/entities/common.ts +28 -0
- package/.claude/skills/generate-api-model/references/entities/index.ts +4 -0
- package/.claude/skills/generate-api-model/references/entities/post/index.ts +2 -0
- package/.claude/skills/generate-api-model/references/entities/post/post-comment.ts +16 -0
- package/.claude/skills/generate-api-model/references/entities/post/post.ts +27 -0
- package/.claude/skills/generate-api-model/references/entities/user/index.ts +3 -0
- package/.claude/skills/generate-api-model/references/entities/user/user-settings.ts +16 -0
- package/.claude/skills/generate-api-model/references/entities/user/user-verification.ts +22 -0
- package/.claude/skills/generate-api-model/references/entities/user/user.ts +26 -0
- package/.claude/skills/generate-api-model/references/resources/common.ts +8 -0
- package/.claude/skills/generate-api-model/references/resources/index.ts +4 -0
- package/.claude/skills/generate-api-model/references/resources/post/index.ts +2 -0
- package/.claude/skills/generate-api-model/references/resources/post/post-comment.ts +8 -0
- package/.claude/skills/generate-api-model/references/resources/post/post.ts +14 -0
- package/.claude/skills/generate-api-model/references/resources/user/index.ts +3 -0
- package/.claude/skills/generate-api-model/references/resources/user/user-settings.ts +8 -0
- package/.claude/skills/generate-api-model/references/resources/user/user-verification.ts +16 -0
- package/.claude/skills/generate-api-model/references/resources/user/user.ts +13 -0
- package/.claude/skills/git-commit/SKILL.md +139 -0
- package/.env +0 -1
- package/.env.example +0 -1
- package/CLAUDE.md +80 -0
- package/env.d.ts +0 -1
- package/expo-env.d.ts +3 -0
- package/i18next.d.ts +1 -1
- package/package.json +44 -43
- package/skills-lock.json +29 -0
- package/src/app/_app.tsx +2 -0
- package/src/shared/assets/icons/like.tsx +1 -1
- package/src/shared/constants/environment.ts +1 -7
- package/src/shared/hooks/use-animated.ts +1 -1
- package/src/shared/hooks/use-safe-area.ts +2 -2
- package/src/shared/lib/api/api.provider.tsx +2 -2
- package/src/shared/lib/api/api.types.ts +1 -1
- package/src/shared/lib/api/entities/common.ts +5 -5
- package/src/shared/lib/api/hooks/common.ts +1 -1
- package/src/shared/lib/api/models/api-instance/api-instance.ts +9 -9
- package/src/shared/lib/api/models/api-instance/api-instance.types.ts +1 -1
- package/src/shared/lib/api/models/api-instance/api-instance.utils.ts +4 -4
- package/src/shared/lib/api/repositories/auth/auth.ts +6 -1
- package/src/shared/lib/api/repositories/auth/auth.types.ts +1 -1
- package/src/shared/lib/api/resources/common.ts +3 -3
- package/src/shared/lib/localization/constants/index.ts +1 -1
- package/src/shared/lib/localization/hooks/use-localization.ts +1 -1
- package/src/shared/lib/localization/localization.provider.tsx +1 -1
- package/src/shared/lib/localization/localization.types.ts +1 -1
- package/src/shared/lib/localization/utils/storage.ts +1 -1
- package/src/shared/lib/navigation/hooks/use-navigation-options.ts +7 -6
- package/src/shared/lib/navigation/navigation.provider.tsx +2 -2
- package/src/shared/lib/navigation/navigation.types.ts +1 -1
- package/src/shared/lib/theme/theme.context.ts +1 -1
- package/src/shared/lib/theme/theme.provider.tsx +21 -6
- package/src/shared/lib/theme/theme.types.ts +2 -2
- package/src/shared/lib/theme/utils/storage.ts +1 -1
- package/src/shared/ui/molecules/keyboard-area/keyboard-area.tsx +1 -1
- package/src/shared/ui/molecules/refresh-control/refresh-control.tsx +1 -1
- package/src/shared/ui/molecules/refresh-control/refresh-control.types.ts +1 -1
- package/src/shared/ui/templates/screen-container/screen-container-list.tsx +1 -1
- package/src/shared/ui/templates/screen-container/screen-container-scroll.tsx +1 -1
- package/src/shared/ui/templates/screen-container/screen-container-section-list.tsx +1 -1
- package/src/shared/ui/templates/screen-container/screen-container.hooks.tsx +3 -3
- package/src/shared/ui/templates/screen-container/screen-container.styles.ts +1 -1
- package/src/shared/ui/templates/screen-container/screen-container.types.tsx +13 -13
- package/svg.d.ts +1 -1
- package/.claude/mcp.json +0 -0
- package/.claude/rules/abstract-skills-agents.mdc +0 -25
- package/src/shared/utils/generators.ts +0 -11
- package/src/shared/utils/index.ts +0 -1
- /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,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:
|
|
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 '
|
|
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,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
|
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
|
|
|
@@ -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
|
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?: () =>
|
|
33
|
+
onRefresh?: () => unknown | Promise<unknown>
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
type ScreenContainerScrollProps = ScreenContainerExcludeExtraNativeProps<ScrollViewProps> &
|
package/svg.d.ts
CHANGED
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 +0,0 @@
|
|
|
1
|
-
export * from './generators'
|
|
File without changes
|