@mediacubeco/expo-template-fsd 2.0.0 → 2.0.2
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/README.md +18 -17
- package/package.json +18 -17
- package/src/app/(root)/(home)/_layout.tsx +15 -0
- package/src/app/(root)/(home)/index.tsx +7 -0
- package/src/app/(root)/(settings)/_layout.tsx +15 -0
- package/src/app/(root)/(settings)/index.tsx +7 -0
- package/src/app/(root)/_layout.tsx +38 -0
- package/src/pages/home/home-main.tsx +18 -0
- package/src/pages/home/index.ts +1 -0
- package/src/pages/settings/index.ts +1 -0
- package/src/pages/settings/settings-main.tsx +18 -0
- package/src/shared/assets/translations/en.ts +10 -1
- package/src/shared/assets/translations/ru.ts +10 -1
- package/src/shared/lib/api/constants/index.ts +1 -4
- package/src/shared/lib/localization/localization.provider.tsx +1 -1
- package/src/shared/lib/navigation/hooks/use-navigation-options.ts +61 -33
- package/src/shared/lib/theme/constants/colors.ts +2 -2
- package/src/shared/lib/theme/constants/index.ts +3 -1
- package/src/shared/lib/theme/theme.provider.tsx +6 -4
- package/src/pages/.gitkeep +0 -0
package/README.md
CHANGED
|
@@ -25,30 +25,31 @@ This project is built on top of the `@mediacubeco/expo-template-fsd` template.
|
|
|
25
25
|
|
|
26
26
|
## Quick Start
|
|
27
27
|
|
|
28
|
-
Run the project from the `templates/expo-template-fsd` directory:
|
|
29
|
-
|
|
30
28
|
```bash
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
npm run postinstall
|
|
32
|
+
|
|
33
|
+
npm run start
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
Then choose a target platform:
|
|
36
37
|
|
|
37
38
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
npm run android
|
|
40
|
+
npm run ios
|
|
41
|
+
npm run web
|
|
41
42
|
```
|
|
42
43
|
|
|
43
44
|
## Scripts
|
|
44
45
|
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
49
|
-
- `
|
|
50
|
-
- `
|
|
51
|
-
- `
|
|
52
|
-
- `
|
|
53
|
-
- `
|
|
54
|
-
- `
|
|
46
|
+
- `npm run prebuild` - Generates native projects with Expo prebuild.
|
|
47
|
+
- `npm run start` - Starts the Expo development server.
|
|
48
|
+
- `npm run android` - Starts the app in Android mode.
|
|
49
|
+
- `npm run android:device` - Runs the Android app on a connected physical device.
|
|
50
|
+
- `npm run ios` - Starts the app in iOS mode.
|
|
51
|
+
- `npm run ios:device` - Runs the iOS app on a connected physical device.
|
|
52
|
+
- `npm run web` - Starts the app in web mode.
|
|
53
|
+
- `npm run format` - Formats the codebase with Prettier.
|
|
54
|
+
- `npm run lint` - Runs ESLint checks.
|
|
55
|
+
- `npm run type` - Runs TypeScript type checking.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"name": "@mediacubeco/expo-template-fsd",
|
|
5
5
|
"description": "Application by Mediacube developers",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"expo-system-ui": "~56.0.5",
|
|
30
30
|
"expo-web-browser": "~56.0.5",
|
|
31
31
|
"i18next": "^26.0.5",
|
|
32
|
-
"react": "
|
|
33
|
-
"react-dom": "
|
|
32
|
+
"react": "19.2.3",
|
|
33
|
+
"react-dom": "19.2.3",
|
|
34
34
|
"react-i18next": "^17.0.3",
|
|
35
|
-
"react-native": "
|
|
35
|
+
"react-native": "0.85.3",
|
|
36
36
|
"react-native-gesture-handler": "~2.31.2",
|
|
37
37
|
"react-native-keyboard-controller": "1.21.6",
|
|
38
38
|
"react-native-reanimated": "4.3.1",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"react-native-svg": "15.15.4",
|
|
42
42
|
"react-native-web": "^0.21.0",
|
|
43
43
|
"react-native-worklets": "0.8.3",
|
|
44
|
-
"@mediacubeco/base-react": "2.0.
|
|
45
|
-
"@mediacubeco/base": "2.0.
|
|
46
|
-
"@mediacubeco/base
|
|
44
|
+
"@mediacubeco/base-react-native": "2.0.2",
|
|
45
|
+
"@mediacubeco/base-react": "2.0.2",
|
|
46
|
+
"@mediacubeco/base": "2.0.2"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/react": "^19.2.0",
|
|
@@ -52,18 +52,19 @@
|
|
|
52
52
|
"husky": "^9.1.7",
|
|
53
53
|
"prettier": "^3.8.1",
|
|
54
54
|
"typescript": "^6.0.3",
|
|
55
|
-
"@mediacubeco/eslint-config-
|
|
56
|
-
"@mediacubeco/eslint-config": "2.0.
|
|
57
|
-
"@mediacubeco/
|
|
58
|
-
"@mediacubeco/
|
|
59
|
-
"@mediacubeco/
|
|
60
|
-
"@mediacubeco/
|
|
61
|
-
"@mediacubeco/typescript-config
|
|
62
|
-
"@mediacubeco/
|
|
63
|
-
"@mediacubeco/typescript-config": "2.0.
|
|
64
|
-
"@mediacubeco/
|
|
55
|
+
"@mediacubeco/eslint-config-react": "2.0.2",
|
|
56
|
+
"@mediacubeco/eslint-config": "2.0.2",
|
|
57
|
+
"@mediacubeco/prettier-config": "2.0.2",
|
|
58
|
+
"@mediacubeco/eslint-config-react-native": "2.0.2",
|
|
59
|
+
"@mediacubeco/prettier-config-fsd": "2.0.2",
|
|
60
|
+
"@mediacubeco/eslint-config-fsd": "2.0.2",
|
|
61
|
+
"@mediacubeco/typescript-config": "2.0.2",
|
|
62
|
+
"@mediacubeco/typescript-config-react": "2.0.2",
|
|
63
|
+
"@mediacubeco/typescript-config-react-native": "2.0.2",
|
|
64
|
+
"@mediacubeco/typescript-config-fsd": "2.0.2"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
|
+
"postinstall": "npx husky && npx skills update",
|
|
67
68
|
"prebuild": "expo prebuild",
|
|
68
69
|
"start": "expo start",
|
|
69
70
|
"android": "expo start --android",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Stack } from 'expo-router'
|
|
2
|
+
import { useLocalizationText, useNavigationStackOptions } from '~shared/lib'
|
|
3
|
+
|
|
4
|
+
const Layout = () => {
|
|
5
|
+
const { createStackOptions, createScreenOptions } = useNavigationStackOptions()
|
|
6
|
+
const t = useLocalizationText()
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<Stack screenOptions={createStackOptions()}>
|
|
10
|
+
<Stack.Screen name={'index'} options={createScreenOptions({ title: t('home.title') })} />
|
|
11
|
+
</Stack>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default Layout
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Stack } from 'expo-router'
|
|
2
|
+
import { useLocalizationText, useNavigationStackOptions } from '~shared/lib'
|
|
3
|
+
|
|
4
|
+
const Layout = () => {
|
|
5
|
+
const { createStackOptions, createScreenOptions } = useNavigationStackOptions()
|
|
6
|
+
const t = useLocalizationText()
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<Stack screenOptions={createStackOptions()}>
|
|
10
|
+
<Stack.Screen name={'index'} options={createScreenOptions({ title: t('settings.title') })} />
|
|
11
|
+
</Stack>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default Layout
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { NativeTabs } from 'expo-router/build/native-tabs'
|
|
2
|
+
import { useLocalizationText, useNavigationTabBarOptions } from '~shared/lib'
|
|
3
|
+
|
|
4
|
+
const Layout = () => {
|
|
5
|
+
const { createTabBarOptions, createTabOptions } = useNavigationTabBarOptions()
|
|
6
|
+
const t = useLocalizationText()
|
|
7
|
+
|
|
8
|
+
const tabBarOptions = createTabBarOptions()
|
|
9
|
+
|
|
10
|
+
const homeTabOptions = createTabOptions({
|
|
11
|
+
name: '(home)',
|
|
12
|
+
children: t('home.title'),
|
|
13
|
+
sf: 'house',
|
|
14
|
+
md: 'home',
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const settingsTabOptions = createTabOptions({
|
|
18
|
+
name: '(settings)',
|
|
19
|
+
children: t('settings.title'),
|
|
20
|
+
sf: 'gear',
|
|
21
|
+
md: 'settings',
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<NativeTabs {...tabBarOptions}>
|
|
26
|
+
<NativeTabs.Trigger {...homeTabOptions.triggerProps}>
|
|
27
|
+
<NativeTabs.Trigger.Label {...homeTabOptions.triggerLabelProps} />
|
|
28
|
+
<NativeTabs.Trigger.Icon {...homeTabOptions.triggerIconProps} />
|
|
29
|
+
</NativeTabs.Trigger>
|
|
30
|
+
<NativeTabs.Trigger {...settingsTabOptions.triggerProps}>
|
|
31
|
+
<NativeTabs.Trigger.Label {...settingsTabOptions.triggerLabelProps} />
|
|
32
|
+
<NativeTabs.Trigger.Icon {...settingsTabOptions.triggerIconProps} />
|
|
33
|
+
</NativeTabs.Trigger>
|
|
34
|
+
</NativeTabs>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default Layout
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Text } from 'react-native'
|
|
2
|
+
import { useLocalizationText, useThemeMode } from '~shared/lib'
|
|
3
|
+
import { ScreenContainerScroll } from '~shared/ui'
|
|
4
|
+
|
|
5
|
+
const HomeMain = () => {
|
|
6
|
+
const t = useLocalizationText()
|
|
7
|
+
const { COLORS } = useThemeMode()
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<ScreenContainerScroll>
|
|
11
|
+
<Text style={{ fontSize: 20, fontWeight: 'bold', color: COLORS.TYPOGRAPHY.BASE }}>
|
|
12
|
+
{t('home.description')}
|
|
13
|
+
</Text>
|
|
14
|
+
</ScreenContainerScroll>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default HomeMain
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as HomeMain } from './home-main'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SettingsMain } from './settings-main'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Text } from 'react-native'
|
|
2
|
+
import { useLocalizationText, useThemeMode } from '~shared/lib'
|
|
3
|
+
import { ScreenContainerScroll } from '~shared/ui/templates'
|
|
4
|
+
|
|
5
|
+
const SettingsMain = () => {
|
|
6
|
+
const t = useLocalizationText()
|
|
7
|
+
const { COLORS } = useThemeMode()
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<ScreenContainerScroll>
|
|
11
|
+
<Text style={{ fontSize: 20, fontWeight: 'bold', color: COLORS.TYPOGRAPHY.BASE }}>
|
|
12
|
+
{t('settings.description')}
|
|
13
|
+
</Text>
|
|
14
|
+
</ScreenContainerScroll>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default SettingsMain
|
|
@@ -3,10 +3,12 @@ import { Platform } from 'react-native'
|
|
|
3
3
|
import { isGlassEffectAPIAvailable } from 'expo-glass-effect'
|
|
4
4
|
import { type StackScreenProps } from 'expo-router'
|
|
5
5
|
import {
|
|
6
|
+
type MaterialIcon,
|
|
6
7
|
type NativeTabsProps,
|
|
7
8
|
type NativeTabsTriggerIconProps,
|
|
8
9
|
type NativeTabsTriggerLabelProps,
|
|
9
10
|
type NativeTabTriggerProps,
|
|
11
|
+
type SFSymbolIcon,
|
|
10
12
|
} from 'expo-router/unstable-native-tabs'
|
|
11
13
|
import { useThemeMode, useThemeSetup } from '../../theme'
|
|
12
14
|
|
|
@@ -14,16 +16,20 @@ const useNavigationStackOptions = () => {
|
|
|
14
16
|
const { COLORS } = useThemeMode()
|
|
15
17
|
const { themeModeSystem } = useThemeSetup()
|
|
16
18
|
|
|
17
|
-
const createStackOptions = useCallback(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const createStackOptions = useCallback(
|
|
20
|
+
(options?: StackScreenProps['options']) => {
|
|
21
|
+
return {
|
|
22
|
+
headerShown: false,
|
|
23
|
+
headerTransparent: false,
|
|
24
|
+
headerShadowVisible: false,
|
|
25
|
+
contentStyle: {
|
|
26
|
+
backgroundColor: COLORS.FILL.BASE,
|
|
27
|
+
},
|
|
28
|
+
...options,
|
|
29
|
+
} satisfies StackScreenProps['options']
|
|
30
|
+
},
|
|
31
|
+
[COLORS]
|
|
32
|
+
)
|
|
27
33
|
|
|
28
34
|
const createScreenOptions = useCallback(
|
|
29
35
|
(options?: StackScreenProps['options']) => {
|
|
@@ -58,33 +64,55 @@ const useNavigationTabBarOptions = () => {
|
|
|
58
64
|
const { COLORS } = useThemeMode()
|
|
59
65
|
const { isThemeModeDark } = useThemeSetup()
|
|
60
66
|
|
|
61
|
-
const createTabBarOptions = useCallback(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
const createTabBarOptions = useCallback(
|
|
68
|
+
(options?: NativeTabsProps) => {
|
|
69
|
+
return {
|
|
70
|
+
sidebarAdaptable: Platform.OS === 'ios',
|
|
71
|
+
disableTransparentOnScrollEdge: Platform.OS === 'ios',
|
|
72
|
+
labelVisibilityMode: 'labeled',
|
|
73
|
+
blurEffect:
|
|
74
|
+
(isGlassEffectAPIAvailable() && 'systemMaterial') ||
|
|
75
|
+
(isThemeModeDark && 'dark') ||
|
|
76
|
+
'light',
|
|
77
|
+
...options,
|
|
78
|
+
} satisfies NativeTabsProps
|
|
79
|
+
},
|
|
80
|
+
[isThemeModeDark]
|
|
81
|
+
)
|
|
70
82
|
|
|
71
|
-
const createTabOptions = useCallback(
|
|
72
|
-
|
|
83
|
+
const createTabOptions = useCallback(
|
|
84
|
+
({
|
|
85
|
+
name,
|
|
86
|
+
children,
|
|
87
|
+
sf,
|
|
88
|
+
md,
|
|
89
|
+
}: NativeTabTriggerProps &
|
|
90
|
+
NativeTabsTriggerLabelProps &
|
|
91
|
+
Partial<SFSymbolIcon> &
|
|
92
|
+
Partial<MaterialIcon> = {}) => {
|
|
93
|
+
const triggerProps = {
|
|
94
|
+
name,
|
|
95
|
+
} satisfies NativeTabTriggerProps
|
|
73
96
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
const triggerLabelProps = {
|
|
98
|
+
hidden: Platform.OS !== 'web',
|
|
99
|
+
children,
|
|
100
|
+
} satisfies NativeTabsTriggerLabelProps
|
|
77
101
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
const triggerIconProps = {
|
|
103
|
+
selectedColor: COLORS.TYPOGRAPHY.PRIMARY,
|
|
104
|
+
sf,
|
|
105
|
+
md,
|
|
106
|
+
} satisfies NativeTabsTriggerIconProps
|
|
81
107
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
108
|
+
return {
|
|
109
|
+
triggerProps,
|
|
110
|
+
triggerLabelProps,
|
|
111
|
+
triggerIconProps,
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
[COLORS]
|
|
115
|
+
)
|
|
88
116
|
|
|
89
117
|
return {
|
|
90
118
|
createTabBarOptions,
|
|
@@ -8,8 +8,8 @@ const PALETTE = {
|
|
|
8
8
|
'LIGHT/SURFACE': '#F5F8FD',
|
|
9
9
|
'LIGHT/FAINT': '#EFF2F7',
|
|
10
10
|
|
|
11
|
-
'LIGHT/PRIMARY': '#
|
|
12
|
-
'LIGHT/PRIMARY_ACTIVE': '#
|
|
11
|
+
'LIGHT/PRIMARY': '#8756FF',
|
|
12
|
+
'LIGHT/PRIMARY_ACTIVE': '#7238FF',
|
|
13
13
|
'LIGHT/PRIMARY_DISABLED': '#D5C9FF',
|
|
14
14
|
|
|
15
15
|
'LIGHT/ACCENT': '#FF2B75',
|
|
@@ -51,4 +51,6 @@ const themes = {
|
|
|
51
51
|
[ThemeModeSystem.Dark]: darkTheme,
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
const hasDarkMode = LIGHT_COLORS !== DARK_COLORS
|
|
55
|
+
|
|
56
|
+
export { ThemeMode, ThemeModeSystem, ThemeModeStatusBar, themes, hasDarkMode }
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Platform } from '@mediacubeco/react-native
|
|
1
|
+
import { Platform } from '@mediacubeco/base-react-native'
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
3
3
|
import { Appearance, StatusBar, useColorScheme } from 'react-native'
|
|
4
4
|
import { themeStorage } from './utils'
|
|
5
|
-
import { ThemeMode, ThemeModeStatusBar, ThemeModeSystem, themes } from './constants'
|
|
5
|
+
import { hasDarkMode, ThemeMode, ThemeModeStatusBar, ThemeModeSystem, themes } from './constants'
|
|
6
6
|
import { ThemeContext } from './theme.context'
|
|
7
7
|
import { type ThemeProviderProps } from './theme.types'
|
|
8
8
|
|
|
9
9
|
const ThemeProvider = ({ children }: ThemeProviderProps) => {
|
|
10
10
|
const didDefine = useRef(false)
|
|
11
|
-
const [themeMode, setThemeMode] = useState(ThemeMode.System)
|
|
11
|
+
const [themeMode, setThemeMode] = useState(hasDarkMode ? ThemeMode.System : ThemeMode.Light)
|
|
12
12
|
const themeModeSystem = (useColorScheme() as ThemeModeSystem) ?? ThemeModeSystem.Light
|
|
13
13
|
|
|
14
14
|
const currentThemeMode = {
|
|
@@ -23,7 +23,9 @@ const ThemeProvider = ({ children }: ThemeProviderProps) => {
|
|
|
23
23
|
|
|
24
24
|
const updateThemeModeSystem = useCallback((themeMode: ThemeMode) => {
|
|
25
25
|
if (Platform.isIos) {
|
|
26
|
-
if (
|
|
26
|
+
if (!hasDarkMode) {
|
|
27
|
+
Appearance.setColorScheme('light')
|
|
28
|
+
} else if (themeMode === ThemeMode.System) {
|
|
27
29
|
Appearance.setColorScheme('unspecified')
|
|
28
30
|
} else {
|
|
29
31
|
Appearance.setColorScheme(themeMode)
|
package/src/pages/.gitkeep
DELETED
|
File without changes
|