mirror of
https://github.com/movie-web/native-app.git
synced 2025-09-13 10:03:26 +00:00
@@ -17,7 +17,7 @@ module.exports = {
|
|||||||
settings: {
|
settings: {
|
||||||
'import/resolver': {
|
'import/resolver': {
|
||||||
typescript: {
|
typescript: {
|
||||||
project: './tsconfig.json',
|
project: ['./tsconfig.base.json', './apps/*/tsconfig.json'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"endOfLine": "auto"
|
"endOfLine": "auto",
|
||||||
|
"plugins": ["prettier-plugin-tailwindcss"]
|
||||||
}
|
}
|
||||||
|
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
@@ -7,5 +7,14 @@
|
|||||||
},
|
},
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
}
|
},
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||||
|
"tailwindCSS.experimental.classRegex": [
|
||||||
|
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
|
||||||
|
["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
|
||||||
|
],
|
||||||
|
"typescript.preferences.autoImportFileExcludePatterns": [
|
||||||
|
// Should import Text from UI components instead
|
||||||
|
"react-native/Libraries/Text/Text.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
1
apps/mobile/app.d.ts
vendored
Normal file
1
apps/mobile/app.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="nativewind/types" />
|
@@ -4,20 +4,19 @@
|
|||||||
"slug": "mw-mobile",
|
"slug": "mw-mobile",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"orientation": "portrait",
|
"orientation": "portrait",
|
||||||
"scheme":"dev.movieweb.app",
|
"scheme": "dev.movieweb.app",
|
||||||
|
"userInterfaceStyle": "automatic",
|
||||||
"icon": "./assets/images/icon.png",
|
"icon": "./assets/images/icon.png",
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/images/splash.png",
|
"image": "./assets/images/splash.png",
|
||||||
"resizeMode": "contain",
|
"resizeMode": "contain",
|
||||||
"backgroundColor": "#ffffff"
|
"backgroundColor": "#ffffff"
|
||||||
},
|
},
|
||||||
"jsEngine": "jsc",
|
"jsEngine": "jsc",
|
||||||
"updates": {
|
"updates": {
|
||||||
"fallbackToCacheTimeout": 0
|
"fallbackToCacheTimeout": 0
|
||||||
},
|
},
|
||||||
"assetBundlePatterns": [
|
"assetBundlePatterns": ["**/*"],
|
||||||
"**/*"
|
|
||||||
],
|
|
||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true,
|
"supportsTablet": true,
|
||||||
"bundleIdentifier": "dev.movieweb.app"
|
"bundleIdentifier": "dev.movieweb.app"
|
||||||
@@ -34,20 +33,17 @@
|
|||||||
"bundler": "metro"
|
"bundler": "metro"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"expo-router",
|
"expo-router",
|
||||||
[
|
[
|
||||||
"@config-plugins/detox",
|
"@config-plugins/detox",
|
||||||
{
|
{
|
||||||
"skipProguard": false,
|
"skipProguard": false,
|
||||||
"subdomains": [
|
"subdomains": ["10.0.2.2", "localhost"]
|
||||||
"10.0.2.2",
|
|
||||||
"localhost"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"experiments": {
|
"experiments": {
|
||||||
"typedRoutes": true
|
"typedRoutes": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,19 @@
|
|||||||
import { Tabs } from 'expo-router';
|
import { Tabs } from 'expo-router';
|
||||||
|
|
||||||
import Colors from '../../constants/Colors';
|
import TabBarIcon from '@/components/TabBarIcon';
|
||||||
import TabBarIcon from '../../components/TabBarIcon';
|
import Colors from '@/constants/Colors';
|
||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
sceneContainerStyle={{
|
sceneContainerStyle={{
|
||||||
backgroundColor: '#000',
|
backgroundColor: Colors.background,
|
||||||
}}
|
}}
|
||||||
screenOptions={{
|
screenOptions={{
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
tabBarActiveTintColor: Colors.dark.purple100,
|
tabBarActiveTintColor: Colors.primary[100],
|
||||||
tabBarStyle: {
|
tabBarStyle: {
|
||||||
backgroundColor: Colors.dark.shade700,
|
backgroundColor: Colors.secondary[700],
|
||||||
borderTopColor: 'transparent',
|
borderTopColor: 'transparent',
|
||||||
borderTopRightRadius: 20,
|
borderTopRightRadius: 20,
|
||||||
borderTopLeftRadius: 20,
|
borderTopLeftRadius: 20,
|
||||||
@@ -28,7 +27,6 @@ export default function TabLayout() {
|
|||||||
{
|
{
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
},
|
},
|
||||||
globalStyles.fOpenSansMedium,
|
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -55,26 +53,9 @@ export default function TabLayout() {
|
|||||||
options={{
|
options={{
|
||||||
title: 'Search',
|
title: 'Search',
|
||||||
tabBarLabel: '',
|
tabBarLabel: '',
|
||||||
tabBarShowLabel: false,
|
|
||||||
tabBarLabelStyle: {
|
|
||||||
display: 'none',
|
|
||||||
},
|
|
||||||
tabBarIconStyle: {},
|
|
||||||
tabBarIcon: () => (
|
tabBarIcon: () => (
|
||||||
<TabBarIcon
|
<TabBarIcon
|
||||||
style={{
|
className=" bg-primary-400 flex aspect-[1/1] h-14 items-center justify-center rounded-full text-center text-2xl text-white"
|
||||||
position: 'relative',
|
|
||||||
top: -1,
|
|
||||||
backgroundColor: Colors.dark.purple400,
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
aspectRatio: 1,
|
|
||||||
borderRadius: 100,
|
|
||||||
textAlign: 'center',
|
|
||||||
textAlignVertical: 'center',
|
|
||||||
height: 56,
|
|
||||||
}}
|
|
||||||
name="search"
|
name="search"
|
||||||
color="#FFF"
|
color="#FFF"
|
||||||
/>
|
/>
|
||||||
|
@@ -1,8 +1,5 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
import ScreenLayout from '@/components/layout/ScreenLayout';
|
||||||
|
import { Text } from '@/components/ui/Text';
|
||||||
import ScreenLayout from '../../components/layout/screenLayout';
|
|
||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
import { RegularText } from '../../components/Styled';
|
|
||||||
|
|
||||||
export default function AboutScreen() {
|
export default function AboutScreen() {
|
||||||
return (
|
return (
|
||||||
@@ -10,27 +7,10 @@ export default function AboutScreen() {
|
|||||||
title="About"
|
title="About"
|
||||||
subtitle="What is movie-web and how content is served?"
|
subtitle="What is movie-web and how content is served?"
|
||||||
>
|
>
|
||||||
<RegularText style={globalStyles.textWhite}>
|
<Text>
|
||||||
No content is served from movie-web directly and movie web does not host
|
No content is served from movie-web directly and movie web does not host
|
||||||
anything.
|
anything.
|
||||||
</RegularText>
|
</Text>
|
||||||
</ScreenLayout>
|
</ScreenLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
marginVertical: 30,
|
|
||||||
height: 1,
|
|
||||||
width: '80%',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
@@ -1,8 +1,5 @@
|
|||||||
import { StyleSheet, Text } from 'react-native';
|
import ScreenLayout from '@/components/layout/ScreenLayout';
|
||||||
|
import { Text } from '@/components/ui/Text';
|
||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
import ScreenLayout from '../../components/layout/screenLayout';
|
|
||||||
import { RegularText } from '../../components/Styled';
|
|
||||||
|
|
||||||
export default function AccountScreen() {
|
export default function AccountScreen() {
|
||||||
return (
|
return (
|
||||||
@@ -10,9 +7,7 @@ export default function AccountScreen() {
|
|||||||
title="Account"
|
title="Account"
|
||||||
subtitle="Manage your movie web account from here"
|
subtitle="Manage your movie web account from here"
|
||||||
>
|
>
|
||||||
<RegularText style={globalStyles.textWhite}>
|
<Text>Hey Bro! what are you up to?</Text>
|
||||||
Hey Bro! what are you up to?
|
|
||||||
</RegularText>
|
|
||||||
</ScreenLayout>
|
</ScreenLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
import { RegularText } from '../../components/Styled';
|
import ScreenLayout from '@/components/layout/ScreenLayout';
|
||||||
import ScreenLayout from '../../components/layout/screenLayout';
|
import { Text } from '@/components/ui/Text';
|
||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
|
|
||||||
export default function HomeScreen() {
|
export default function HomeScreen() {
|
||||||
return (
|
return (
|
||||||
<ScreenLayout title="Home" subtitle="This is where all magic happens">
|
<ScreenLayout title="Home" subtitle="This is where all magic happens">
|
||||||
<RegularText style={globalStyles.textWhite}>
|
<Text>Movies will be listed here</Text>
|
||||||
Movies will be listed here
|
|
||||||
</RegularText>
|
|
||||||
</ScreenLayout>
|
</ScreenLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import { FontAwesome5 } from '@expo/vector-icons';
|
import { FontAwesome5 } from '@expo/vector-icons';
|
||||||
|
import { useFocusEffect } from 'expo-router';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
import { useCallback, useRef, useState } from 'react';
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import { TextInput } from 'react-native-gesture-handler';
|
import { TextInput } from 'react-native-gesture-handler';
|
||||||
import { globalStyles } from '../../../styles/global';
|
|
||||||
import Colors from '../../../constants/Colors';
|
import Colors from '@/constants/Colors';
|
||||||
import { useFocusEffect } from 'expo-router';
|
|
||||||
|
|
||||||
export default function Searchbar() {
|
export default function Searchbar() {
|
||||||
const [keyword, setKeyword] = useState('');
|
const [keyword, setKeyword] = useState('');
|
||||||
@@ -24,41 +24,19 @@ export default function Searchbar() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View className="border-primary-400 focus-within:border-primary-300 mb-6 mt-4 flex-row items-center rounded-full border">
|
||||||
style={{
|
<View className="ml-1 w-12 items-center justify-center">
|
||||||
...globalStyles.flexRow,
|
<FontAwesome5 name="search" size={18} color={Colors.secondary[200]} />
|
||||||
...globalStyles.itemsCenter,
|
|
||||||
...globalStyles.border,
|
|
||||||
...globalStyles.roundedFull,
|
|
||||||
marginTop: 14,
|
|
||||||
marginBottom: 24,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
...globalStyles.justifyCenter,
|
|
||||||
...globalStyles.itemsCenter,
|
|
||||||
width: 48,
|
|
||||||
marginLeft: 4,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FontAwesome5 name="search" size={18} color={Colors.dark.shade200} />
|
|
||||||
</View>
|
</View>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={keyword}
|
value={keyword}
|
||||||
autoFocus={true}
|
autoFocus
|
||||||
onChangeText={(text) => setKeyword(text)}
|
onChangeText={(text) => setKeyword(text)}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder="What are you looking for?"
|
placeholder="What are you looking for?"
|
||||||
placeholderTextColor={Colors.dark.shade200}
|
placeholderTextColor={Colors.secondary[200]}
|
||||||
style={[
|
className="w-full rounded-3xl py-3 pr-5 text-white focus-visible:outline-none"
|
||||||
globalStyles.input,
|
/>
|
||||||
globalStyles.fOpenSansRegular,
|
|
||||||
{
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
></TextInput>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,9 @@
|
|||||||
import { Dimensions, ScrollView, View } from 'react-native';
|
import { ScrollView, View } from 'react-native';
|
||||||
|
|
||||||
|
import Item from '@/components/item/item';
|
||||||
|
import ScreenLayout from '@/components/layout/ScreenLayout';
|
||||||
|
import { Text } from '@/components/ui/Text';
|
||||||
|
|
||||||
import { globalStyles } from '../../../styles/global';
|
|
||||||
import ScreenLayout from '../../../components/layout/screenLayout';
|
|
||||||
import { TextInput } from 'react-native-gesture-handler';
|
|
||||||
import styles from './styles';
|
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
||||||
import { useFocusEffect } from 'expo-router';
|
|
||||||
import { BoldText } from '../../../components/Styled';
|
|
||||||
import Item from '../../../components/item/item';
|
|
||||||
import Searchbar from './Searchbar';
|
import Searchbar from './Searchbar';
|
||||||
|
|
||||||
export default function SearchScreen() {
|
export default function SearchScreen() {
|
||||||
@@ -15,23 +11,21 @@ export default function SearchScreen() {
|
|||||||
<ScrollView>
|
<ScrollView>
|
||||||
<ScreenLayout
|
<ScreenLayout
|
||||||
title={
|
title={
|
||||||
<View
|
<View className="flex-row items-center">
|
||||||
style={{ ...globalStyles.flexRow, ...globalStyles.itemsCenter }}
|
<Text className="text-2xl font-bold">Search</Text>
|
||||||
>
|
|
||||||
<BoldText style={globalStyles.sectionTitle}>Search</BoldText>
|
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
subtitle="Looking for something?"
|
subtitle="Looking for something?"
|
||||||
>
|
>
|
||||||
<Searchbar />
|
<Searchbar />
|
||||||
<View style={styles.items}>
|
<View className="flex w-full flex-1 flex-row flex-wrap justify-start">
|
||||||
<View style={styles.itemOuter}>
|
<View className="basis-1/2 px-3 pb-3">
|
||||||
<Item />
|
<Item />
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.itemOuter}>
|
<View className="basis-1/2 px-3 pb-3">
|
||||||
<Item />
|
<Item />
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.itemOuter}>
|
<View className="basis-1/2 px-3 pb-3">
|
||||||
<Item />
|
<Item />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
items: {
|
|
||||||
display: 'flex',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
justifyContent: 'flex-start',
|
|
||||||
width: '100%',
|
|
||||||
flexDirection: 'row',
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
itemOuter: {
|
|
||||||
flexBasis: '50%',
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
paddingBottom: 12,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default styles;
|
|
@@ -1,14 +1,10 @@
|
|||||||
import { RegularText } from '../../components/Styled';
|
import ScreenLayout from '@/components/layout/ScreenLayout';
|
||||||
import ScreenLayout from '../../components/layout/screenLayout';
|
import { Text } from '@/components/ui/Text';
|
||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
import { StyleSheet, Text } from 'react-native';
|
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
return (
|
return (
|
||||||
<ScreenLayout title="Settings" subtitle="Need to change something?">
|
<ScreenLayout title="Settings" subtitle="Need to change something?">
|
||||||
<RegularText style={globalStyles.textWhite}>
|
<Text>Settings would be listed in here. Coming soon</Text>
|
||||||
Settings would be listed in here. Coming soon
|
|
||||||
</RegularText>
|
|
||||||
</ScreenLayout>
|
</ScreenLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,41 +1,21 @@
|
|||||||
import { Link, Stack } from 'expo-router';
|
import { Link, Stack } from 'expo-router';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import { BoldText, RegularText } from '../components/Styled';
|
|
||||||
|
import { Text } from '@/components/ui/Text';
|
||||||
|
|
||||||
export default function NotFoundScreen() {
|
export default function NotFoundScreen() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen options={{ title: 'Oops!' }} />
|
<Stack.Screen options={{ title: 'Oops!' }} />
|
||||||
<View style={styles.container}>
|
<View className="flex-1 items-center justify-center p-5">
|
||||||
<BoldText style={styles.title}>
|
<Text className="text-lg font-bold">
|
||||||
This screen doesn't exist.
|
This screen doesn't exist.
|
||||||
</BoldText>
|
</Text>
|
||||||
|
|
||||||
<Link href="/" style={styles.link}>
|
<Link href="/" className="mt-4 py-4">
|
||||||
<RegularText style={styles.linkText}>Go to home screen!</RegularText>
|
<Text className="text-sm text-sky-500">Go to home screen!</Text>
|
||||||
</Link>
|
</Link>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: 20,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
marginTop: 15,
|
|
||||||
paddingVertical: 15,
|
|
||||||
},
|
|
||||||
linkText: {
|
|
||||||
fontSize: 14,
|
|
||||||
color: '#2e78b7',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable global-require */
|
||||||
import FontAwesome from '@expo/vector-icons/FontAwesome';
|
import FontAwesome from '@expo/vector-icons/FontAwesome';
|
||||||
import {
|
import {
|
||||||
DarkTheme,
|
DarkTheme,
|
||||||
@@ -9,7 +10,9 @@ import { SplashScreen, Stack } from 'expo-router';
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useColorScheme } from 'react-native';
|
import { useColorScheme } from 'react-native';
|
||||||
|
|
||||||
import Colors from '../constants/Colors';
|
import Colors from '@/constants/Colors';
|
||||||
|
|
||||||
|
import './styles/global.css';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// Catch any errors thrown by the Layout component.
|
// Catch any errors thrown by the Layout component.
|
||||||
@@ -27,7 +30,6 @@ SplashScreen.preventAutoHideAsync();
|
|||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
const [loaded, error] = useFonts({
|
const [loaded, error] = useFonts({
|
||||||
// eslint-disable-next-line global-require
|
|
||||||
OpenSansRegular: require('../assets/fonts/OpenSans-Regular.ttf'),
|
OpenSansRegular: require('../assets/fonts/OpenSans-Regular.ttf'),
|
||||||
OpenSansLight: require('../assets/fonts/OpenSans-Light.ttf'),
|
OpenSansLight: require('../assets/fonts/OpenSans-Light.ttf'),
|
||||||
OpenSansMedium: require('../assets/fonts/OpenSans-Medium.ttf'),
|
OpenSansMedium: require('../assets/fonts/OpenSans-Medium.ttf'),
|
||||||
@@ -65,12 +67,11 @@ function RootLayoutNav() {
|
|||||||
gestureEnabled: true,
|
gestureEnabled: true,
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
contentStyle: {
|
contentStyle: {
|
||||||
backgroundColor: Colors.dark.shade900,
|
backgroundColor: Colors.background,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
@@ -13,7 +13,6 @@ export function ExternalLink(
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
// @ts-expect-error: External URLs are not typed.
|
|
||||||
href={props.href}
|
href={props.href}
|
||||||
onPress={(e) => {
|
onPress={(e) => {
|
||||||
if (Platform.OS !== 'web') {
|
if (Platform.OS !== 'web') {
|
17
apps/mobile/app/components/TabBarIcon.tsx
Normal file
17
apps/mobile/app/components/TabBarIcon.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { FontAwesome } from '@expo/vector-icons';
|
||||||
|
|
||||||
|
import Colors from '@/constants/Colors';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
focused?: boolean;
|
||||||
|
} & React.ComponentProps<typeof FontAwesome>;
|
||||||
|
|
||||||
|
export default function TabBarIcon({ focused, ...rest }: Props) {
|
||||||
|
return (
|
||||||
|
<FontAwesome
|
||||||
|
color={focused ? Colors.primary[300] : Colors.secondary[300]}
|
||||||
|
size={24}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
26
apps/mobile/app/components/item/item.tsx
Normal file
26
apps/mobile/app/components/item/item.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Image, View } from 'react-native';
|
||||||
|
|
||||||
|
import { Text } from '@/components/ui/Text';
|
||||||
|
import { TMDB_POSTER_PATH } from '@/constants/General';
|
||||||
|
|
||||||
|
export default function Item() {
|
||||||
|
return (
|
||||||
|
<View className="w-full">
|
||||||
|
<View className="mb-2 aspect-[9/14] w-full overflow-hidden rounded-2xl">
|
||||||
|
<Image
|
||||||
|
source={{
|
||||||
|
uri: `${TMDB_POSTER_PATH}/w342//gdIrmf2DdY5mgN6ycVP0XlzKzbE.jpg`,
|
||||||
|
width: 200,
|
||||||
|
}}
|
||||||
|
className="h-full w-full object-cover"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text className="font-bold">Hamilton</Text>
|
||||||
|
<View className="flex-row items-center gap-3">
|
||||||
|
<Text className="text-xs text-gray-600">Movie</Text>
|
||||||
|
<View className="h-1 w-1 rounded-3xl bg-gray-600" />
|
||||||
|
<Text className="text-sm text-gray-600">2023</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
22
apps/mobile/app/components/layout/ScreenLayout.tsx
Normal file
22
apps/mobile/app/components/layout/ScreenLayout.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
import { Text } from '@/components/ui/Text';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title?: React.ReactNode | string;
|
||||||
|
subtitle?: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ScreenLayout({ title, subtitle, children }: Props) {
|
||||||
|
return (
|
||||||
|
<View className="bg-shade-900 flex-1 p-12">
|
||||||
|
{typeof title === 'string' && (
|
||||||
|
<Text className="text-2xl font-bold">{title}</Text>
|
||||||
|
)}
|
||||||
|
{typeof title !== 'string' && title}
|
||||||
|
<Text className="mt-1 text-sm font-bold">{subtitle}</Text>
|
||||||
|
<View className="py-3">{children}</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
17
apps/mobile/app/components/ui/Text.tsx
Normal file
17
apps/mobile/app/components/ui/Text.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { cva } from 'class-variance-authority';
|
||||||
|
import { Text as RNText, TextProps } from 'react-native';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const textVariants = cva('text-white');
|
||||||
|
|
||||||
|
export function Text({ className, ...props }: TextProps) {
|
||||||
|
return (
|
||||||
|
<RNText
|
||||||
|
className={cn(className, textVariants(), {
|
||||||
|
'font-sans': !className?.includes('font-'),
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
14
apps/mobile/app/constants/Colors.ts
Normal file
14
apps/mobile/app/constants/Colors.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export default {
|
||||||
|
primary: {
|
||||||
|
100: '#C082FF',
|
||||||
|
300: '#8D44D6',
|
||||||
|
400: '#7831BF',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
50: '#676790',
|
||||||
|
200: '#3F3F60',
|
||||||
|
300: '#32324F',
|
||||||
|
700: '#131322',
|
||||||
|
},
|
||||||
|
background: '#0a0a12',
|
||||||
|
};
|
@@ -1 +1 @@
|
|||||||
export const TMDB_POSTER_PATH = `https://image.tmdb.org/t/p`;
|
export const TMDB_POSTER_PATH = `https://image.tmdb.org/t/p`;
|
6
apps/mobile/app/lib/utils.ts
Normal file
6
apps/mobile/app/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { ClassValue, clsx } from 'clsx';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
@@ -1,33 +0,0 @@
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
|
||||||
import { Platform, StyleSheet, View } from 'react-native';
|
|
||||||
import { BoldText, RegularText } from '../components/Styled';
|
|
||||||
|
|
||||||
export default function ModalScreen() {
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
<BoldText style={styles.title}>Modal</BoldText>
|
|
||||||
<View style={styles.separator} />
|
|
||||||
<RegularText>Modal?!</RegularText>
|
|
||||||
|
|
||||||
{/* Use a light status bar on iOS to account for the black space above the modal */}
|
|
||||||
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
marginVertical: 30,
|
|
||||||
height: 1,
|
|
||||||
width: '80%',
|
|
||||||
},
|
|
||||||
});
|
|
3
apps/mobile/app/styles/global.css
Normal file
3
apps/mobile/app/styles/global.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
@@ -1,10 +1,14 @@
|
|||||||
module.exports = function (api) {
|
module.exports = function (api) {
|
||||||
api.cache(true);
|
api.cache(true);
|
||||||
return {
|
return {
|
||||||
presets: ['babel-preset-expo'],
|
presets: [
|
||||||
plugins: [
|
['babel-preset-expo', { jsxImportSource: 'nativewind' }],
|
||||||
// Required for expo-router
|
'nativewind/babel',
|
||||||
'expo-router/babel',
|
],
|
||||||
],
|
plugins: [
|
||||||
|
// Required for expo-router
|
||||||
|
'expo-router/babel',
|
||||||
|
'react-native-reanimated/plugin',
|
||||||
|
],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -1,44 +0,0 @@
|
|||||||
import { Text } from 'react-native';
|
|
||||||
|
|
||||||
export const RegularText = ({ style, children, ...rest }: Text['props']) => {
|
|
||||||
return (
|
|
||||||
<Text style={[{ fontFamily: 'OpenSansRegular' }, style]} {...rest}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const BoldText = ({ style, children, ...rest }: Text['props']) => {
|
|
||||||
return (
|
|
||||||
<Text style={[{ fontFamily: 'OpenSansBold' }, style]} {...rest}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const SemiBoldText = ({ style, children, ...rest }: Text['props']) => {
|
|
||||||
return (
|
|
||||||
<Text style={[{ fontFamily: 'OpenSansSemiBold' }, style]} {...rest}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const MediumText = ({ style, children, ...rest }: Text['props']) => {
|
|
||||||
return (
|
|
||||||
<Text style={[{ fontFamily: 'OpenSansMedium' }, style]} {...rest}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const ExtraBoldText = ({ style, children, ...rest }: Text['props']) => {
|
|
||||||
return (
|
|
||||||
<Text style={[{ fontFamily: 'OpenSansExtraBold' }, style]} {...rest}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const LightText = ({ style, children, ...rest }: Text['props']) => {
|
|
||||||
return (
|
|
||||||
<Text style={[{ fontFamily: 'OpenSansLight' }, style]} {...rest}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
@@ -1,21 +0,0 @@
|
|||||||
import { FontAwesome } from '@expo/vector-icons';
|
|
||||||
import Colors from '../constants/Colors';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
focused?: boolean;
|
|
||||||
color?: string;
|
|
||||||
} & React.ComponentProps<typeof FontAwesome>;
|
|
||||||
|
|
||||||
export default function TabBarIcon({
|
|
||||||
color = Colors.dark.shade300,
|
|
||||||
focused,
|
|
||||||
...rest
|
|
||||||
}: Props) {
|
|
||||||
return (
|
|
||||||
<FontAwesome
|
|
||||||
color={color || (focused ? Colors.dark.purple300 : Colors.dark.shade300)}
|
|
||||||
size={24}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
import { Image, Text, View } from 'react-native';
|
|
||||||
import styles from './styles';
|
|
||||||
import { BoldText, RegularText } from '../Styled';
|
|
||||||
import { TMDB_POSTER_PATH } from '../../constants/General';
|
|
||||||
|
|
||||||
export default function Item() {
|
|
||||||
return (
|
|
||||||
<View style={styles.wrapper}>
|
|
||||||
<View style={styles.imageWrapper}>
|
|
||||||
<Image
|
|
||||||
source={{
|
|
||||||
uri: `${TMDB_POSTER_PATH}/w342//gdIrmf2DdY5mgN6ycVP0XlzKzbE.jpg`,
|
|
||||||
width: 200,
|
|
||||||
}}
|
|
||||||
style={styles.image}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<BoldText style={globalStyles.textWhite}>Hamilton</BoldText>
|
|
||||||
<View style={styles.meta}>
|
|
||||||
<RegularText style={[globalStyles.textMuted, styles.smallText]}>
|
|
||||||
Movie
|
|
||||||
</RegularText>
|
|
||||||
<View style={[globalStyles.dotSeperator]}></View>
|
|
||||||
<RegularText style={[globalStyles.textMuted, styles.smallText]}>
|
|
||||||
2023
|
|
||||||
</RegularText>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
import Colors from '../../constants/Colors';
|
|
||||||
import { StyleSheet } from 'react-native';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
wrapper: {
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
imageWrapper: {
|
|
||||||
borderRadius: 16,
|
|
||||||
aspectRatio: 9 / 14,
|
|
||||||
width: '100%',
|
|
||||||
overflow: 'hidden',
|
|
||||||
position: 'relative',
|
|
||||||
marginBottom: 6,
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
resizeMode: 'cover',
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
gap: 6,
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
smallText: {
|
|
||||||
fontSize: 12,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default styles;
|
|
@@ -1,31 +0,0 @@
|
|||||||
import { View } from 'react-native';
|
|
||||||
import { globalStyles } from '../../styles/global';
|
|
||||||
import { styles } from './styles';
|
|
||||||
import { BoldText, RegularText } from '../Styled';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
title?: React.ReactNode | string;
|
|
||||||
subtitle?: string;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ScreenLayout({ title, subtitle, children }: Props) {
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
globalStyles.pageContainer,
|
|
||||||
globalStyles.container,
|
|
||||||
styles.container,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{typeof title === 'string' && (
|
|
||||||
<BoldText style={globalStyles.sectionTitle}>{title}</BoldText>
|
|
||||||
)}
|
|
||||||
{typeof title !== 'string' && title}
|
|
||||||
<RegularText style={[{ marginTop: 4 }, globalStyles.sectionSubtitle]}>
|
|
||||||
{subtitle}
|
|
||||||
</RegularText>
|
|
||||||
<View style={styles.children}>{children}</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
import { Dimensions, StyleSheet } from 'react-native';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
minHeight: Dimensions.get('window').height,
|
|
||||||
},
|
|
||||||
children: {
|
|
||||||
paddingVertical: 12,
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,27 +0,0 @@
|
|||||||
const tintColorLight = '#2f95dc';
|
|
||||||
const tintColorDark = '#fff';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
light: {
|
|
||||||
text: '#000',
|
|
||||||
background: '#fff',
|
|
||||||
tint: tintColorLight,
|
|
||||||
tabIconDefault: '#ccc',
|
|
||||||
tabIconSelected: tintColorLight,
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
text: '#fff',
|
|
||||||
background: '#000',
|
|
||||||
tint: tintColorDark,
|
|
||||||
tabIconDefault: '#ccc',
|
|
||||||
tabIconSelected: tintColorDark,
|
|
||||||
purple100: '#C082FF',
|
|
||||||
purple300: '#8D44D6',
|
|
||||||
purple400: '#7831BF',
|
|
||||||
shade50: '#676790',
|
|
||||||
shade200: '#3F3F60',
|
|
||||||
shade300: '#32324F',
|
|
||||||
shade700: '#131322',
|
|
||||||
shade900: '#0A0A12',
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,9 +1,12 @@
|
|||||||
const { withNxMetro } = require('@nx/expo');
|
const { withNxMetro } = require('@nx/expo');
|
||||||
const { getDefaultConfig } = require('@expo/metro-config');
|
const { getDefaultConfig } = require('@expo/metro-config');
|
||||||
const { mergeConfig } = require('metro-config');
|
const { mergeConfig } = require('metro-config');
|
||||||
|
const { withNativeWind } = require('nativewind/metro');
|
||||||
const exclusionList = require('metro-config/src/defaults/exclusionList');
|
const exclusionList = require('metro-config/src/defaults/exclusionList');
|
||||||
|
|
||||||
const defaultConfig = getDefaultConfig(__dirname);
|
const defaultConfig = getDefaultConfig(__dirname, {
|
||||||
|
isCSSEnabled: true,
|
||||||
|
});
|
||||||
const { assetExts, sourceExts } = defaultConfig.resolver;
|
const { assetExts, sourceExts } = defaultConfig.resolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,14 +21,22 @@ const customConfig = {
|
|||||||
},
|
},
|
||||||
resolver: {
|
resolver: {
|
||||||
assetExts: assetExts.filter((ext) => ext !== 'svg'),
|
assetExts: assetExts.filter((ext) => ext !== 'svg'),
|
||||||
sourceExts: [...sourceExts, 'svg'],
|
sourceExts: [...sourceExts, 'svg', 'mjs'],
|
||||||
blockList: exclusionList([/^(?!.*node_modules).*\/dist\/.*/]),
|
blockList: exclusionList([/^(?!.*node_modules).*\/dist\/.*/]),
|
||||||
// unstable_enableSymlinks: true,
|
// unstable_enableSymlinks: true,
|
||||||
// unstable_enablePackageExports: true,
|
// unstable_enablePackageExports: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
|
const nativeWindConfig = withNativeWind(
|
||||||
|
mergeConfig(defaultConfig, customConfig),
|
||||||
|
{
|
||||||
|
input: './app/styles/global.css',
|
||||||
|
configPath: './tailwind.config.ts',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const nxConfig = withNxMetro(nativeWindConfig, {
|
||||||
// Change this to true to see debugging info.
|
// Change this to true to see debugging info.
|
||||||
// Useful if you have issues resolving modules
|
// Useful if you have issues resolving modules
|
||||||
debug: false,
|
debug: false,
|
||||||
@@ -34,3 +45,4 @@ module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
|
|||||||
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
|
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
|
||||||
watchFolders: [],
|
watchFolders: [],
|
||||||
});
|
});
|
||||||
|
module.exports = nxConfig;
|
||||||
|
@@ -12,8 +12,15 @@
|
|||||||
"@expo/vector-icons": "^13.0.0",
|
"@expo/vector-icons": "^13.0.0",
|
||||||
"@nx/expo": "*",
|
"@nx/expo": "*",
|
||||||
"@react-navigation/native": "^6.1.9",
|
"@react-navigation/native": "^6.1.9",
|
||||||
|
"@rnx-kit/metro-config": "*",
|
||||||
|
"@rnx-kit/metro-resolver-symlinks": "*",
|
||||||
"@testing-library/jest-native": "*",
|
"@testing-library/jest-native": "*",
|
||||||
"@testing-library/react-native": "*",
|
"@testing-library/react-native": "*",
|
||||||
|
"@types/react": "*",
|
||||||
|
"class-variance-authority": "^0.7.0",
|
||||||
|
"clsx": "^2.1.0",
|
||||||
|
"eslint-plugin-react": "*",
|
||||||
|
"eslint-plugin-react-hooks": "*",
|
||||||
"expo": "*",
|
"expo": "*",
|
||||||
"expo-font": "^11.4.0",
|
"expo-font": "^11.4.0",
|
||||||
"expo-linking": "^5.0.2",
|
"expo-linking": "^5.0.2",
|
||||||
@@ -22,26 +29,27 @@
|
|||||||
"expo-status-bar": "*",
|
"expo-status-bar": "*",
|
||||||
"expo-system-ui": "^2.6.0",
|
"expo-system-ui": "^2.6.0",
|
||||||
"expo-web-browser": "^12.5.0",
|
"expo-web-browser": "^12.5.0",
|
||||||
|
"jest": "*",
|
||||||
|
"jest-expo": "*",
|
||||||
|
"metro": "*",
|
||||||
"metro-config": "*",
|
"metro-config": "*",
|
||||||
|
"nativewind": "^4.0.23",
|
||||||
"pod-install": "*",
|
"pod-install": "*",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-gesture-handler": "^2.14.1",
|
"react-native-gesture-handler": "^2.14.1",
|
||||||
|
"react-native-reanimated": "~3.3.0",
|
||||||
"react-native-safe-area-context": "^4.8.2",
|
"react-native-safe-area-context": "^4.8.2",
|
||||||
"react-native-screens": "^3.29.0",
|
"react-native-screens": "^3.29.0",
|
||||||
"react-native-svg": "*",
|
"react-native-svg": "*",
|
||||||
"react-native-svg-transformer": "*",
|
"react-native-svg-transformer": "*",
|
||||||
"react-native-web": "^0.19.10",
|
"react-native-web": "^0.19.10",
|
||||||
"@rnx-kit/metro-config": "*",
|
|
||||||
"@rnx-kit/metro-resolver-symlinks": "*",
|
|
||||||
"@types/react": "*",
|
|
||||||
"eslint-plugin-react": "*",
|
|
||||||
"eslint-plugin-react-hooks": "*",
|
|
||||||
"jest": "*",
|
|
||||||
"jest-expo": "*",
|
|
||||||
"react-test-renderer": "*",
|
"react-test-renderer": "*",
|
||||||
"typescript": "*"
|
"tailwind-merge": "^2.2.1",
|
||||||
|
"tailwindcss": "3.3.2",
|
||||||
|
"typescript": "*",
|
||||||
|
"prettier-plugin-tailwindcss": "*"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"eas-build-pre-install": "cd ../../ && node tools/scripts/eas-build-pre-install.mjs . apps/mobile && cp pnpm-lock.yaml apps/mobile",
|
"eas-build-pre-install": "cd ../../ && node tools/scripts/eas-build-pre-install.mjs . apps/mobile && cp pnpm-lock.yaml apps/mobile",
|
||||||
@@ -62,13 +70,8 @@
|
|||||||
"jest": "^29.4.1",
|
"jest": "^29.4.1",
|
||||||
"jest-expo": "~49.0.0",
|
"jest-expo": "~49.0.0",
|
||||||
"pod-install": "^0.1.39",
|
"pod-install": "^0.1.39",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||||
"react-test-renderer": "18.2.0",
|
"react-test-renderer": "18.2.0",
|
||||||
"typescript": "~5.2.2"
|
"typescript": "~5.2.2"
|
||||||
},
|
|
||||||
"overrides": {
|
|
||||||
"react-refresh": "~0.14.0"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"react-refresh": "~0.14.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,8 @@
|
|||||||
"executor": "@nx/expo:start",
|
"executor": "@nx/expo:start",
|
||||||
"dependsOn": ["ensure-symlink", "sync-deps"],
|
"dependsOn": ["ensure-symlink", "sync-deps"],
|
||||||
"options": {
|
"options": {
|
||||||
"port": 8081
|
"port": 8081,
|
||||||
|
"clear": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
|
@@ -1,75 +0,0 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
|
||||||
import Colors from '../constants/Colors';
|
|
||||||
|
|
||||||
export const globalStyles = StyleSheet.create({
|
|
||||||
pageContainer: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: Colors.dark.shade900,
|
|
||||||
paddingVertical: 48,
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: 24,
|
|
||||||
},
|
|
||||||
sectionTitle: {
|
|
||||||
color: '#FFF',
|
|
||||||
letterSpacing: -1.5,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontSize: 28,
|
|
||||||
},
|
|
||||||
sectionSubtitle: {
|
|
||||||
color: Colors.dark.shade200,
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
textWhite: {
|
|
||||||
color: '#FFF',
|
|
||||||
},
|
|
||||||
flexRow: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
itemsCenter: {
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
justifyCenter: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
input: {
|
|
||||||
borderRadius: 24,
|
|
||||||
paddingRight: 18,
|
|
||||||
paddingVertical: 12,
|
|
||||||
color: '#FFF',
|
|
||||||
},
|
|
||||||
border: {
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: 'rgba(255,255,255,.1)',
|
|
||||||
},
|
|
||||||
roundedFull: {
|
|
||||||
borderRadius: 34,
|
|
||||||
},
|
|
||||||
fOpenSansLight: {
|
|
||||||
fontFamily: 'OpenSansLight',
|
|
||||||
},
|
|
||||||
fOpenSansBold: {
|
|
||||||
fontFamily: 'OpenSansBold',
|
|
||||||
},
|
|
||||||
fOpenSansSemiBold: {
|
|
||||||
fontFamily: 'OpenSansSemiBold',
|
|
||||||
},
|
|
||||||
fOpenSansMedium: {
|
|
||||||
fontFamily: 'OpenSansMedium',
|
|
||||||
},
|
|
||||||
fOpenSansExtraBold: {
|
|
||||||
fontFamily: 'OpenSansExtraBold',
|
|
||||||
},
|
|
||||||
fOpenSansRegular: {
|
|
||||||
fontFamily: 'OpenSansRegular',
|
|
||||||
},
|
|
||||||
textMuted: {
|
|
||||||
color: '#5F5F7A',
|
|
||||||
},
|
|
||||||
dotSeperator: {
|
|
||||||
width: 4,
|
|
||||||
height: 4,
|
|
||||||
backgroundColor: '#5F5F7A',
|
|
||||||
borderRadius: 50,
|
|
||||||
},
|
|
||||||
});
|
|
27
apps/mobile/tailwind.config.ts
Normal file
27
apps/mobile/tailwind.config.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// @ts-expect-error - no types
|
||||||
|
import nativewind from 'nativewind/preset';
|
||||||
|
import type { Config } from 'tailwindcss';
|
||||||
|
import colors from './app/constants/Colors';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
content: ['./app/**/*.{js,jsx,ts,tsx}'],
|
||||||
|
presets: [
|
||||||
|
nativewind,
|
||||||
|
{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors,
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['OpenSansRegular'],
|
||||||
|
thin: ['OpenSansLight'],
|
||||||
|
normal: ['OpenSansRegular'],
|
||||||
|
medium: ['OpenSansMedium'],
|
||||||
|
semibold: ['OpenSansSemiBold'],
|
||||||
|
bold: ['OpenSansBold'],
|
||||||
|
extrabold: ['OpenSansExtra'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} satisfies Config;
|
@@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
"types": ["node"]
|
"types": ["node"],
|
||||||
},
|
},
|
||||||
"files": ["../../node_modules/@nx/expo/typings/svg.d.ts"],
|
"files": ["../../node_modules/@nx/expo/typings/svg.d.ts"],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
@@ -11,5 +12,11 @@
|
|||||||
"**/*.spec.tsx",
|
"**/*.spec.tsx",
|
||||||
"test-setup.ts"
|
"test-setup.ts"
|
||||||
],
|
],
|
||||||
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
"**/*.js",
|
||||||
|
"**/*.jsx",
|
||||||
|
"tailwind.config.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@@ -3,27 +3,28 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"jsx": "react-native",
|
"jsx": "react-native",
|
||||||
"lib": [
|
"lib": ["dom", "esnext"],
|
||||||
"dom",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"declaration": true
|
"declaration": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"./app/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"files": [],
|
"files": [],
|
||||||
"include": [
|
"include": [".expo/types/**/*.ts", "expo-env.d.ts"],
|
||||||
".expo/types/**/*.ts",
|
|
||||||
"expo-env.d.ts"
|
|
||||||
],
|
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "./tsconfig.app.json"
|
"path": "./tsconfig.app.json",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./tsconfig.spec.json"
|
"path": "./tsconfig.spec.json",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"types": ["jest", "node"]
|
"types": ["jest", "node"]
|
||||||
|
11
package.json
11
package.json
@@ -60,5 +60,16 @@
|
|||||||
"react-native-svg-transformer": "1.3.0",
|
"react-native-svg-transformer": "1.3.0",
|
||||||
"react-native-web": "~0.19.9",
|
"react-native-web": "~0.19.9",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"patchedDependencies": {
|
||||||
|
"nativewind@4.0.23": "patches/nativewind@4.0.23.patch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"react-refresh": "~0.14.0"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"react-refresh": "~0.14.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
patches/nativewind@4.0.23.patch
Normal file
13
patches/nativewind@4.0.23.patch
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/dist/metro/transformer.js b/dist/metro/transformer.js
|
||||||
|
index 1bda43b116d02834db01a42e64dd302e3d3fe785..8ff7f8a324cd9a8531df915a704d604828959e78 100644
|
||||||
|
--- a/dist/metro/transformer.js
|
||||||
|
+++ b/dist/metro/transformer.js
|
||||||
|
@@ -16,7 +16,7 @@ new globalThis.WebSocket(\`\${url}:${config.nativewind.fastRefreshPort}\`).addEv
|
||||||
|
StyleSheet.registerCompiled(JSON.parse('${config.nativewind.parsedOutput}'));`, "utf8"), options);
|
||||||
|
}
|
||||||
|
else if (options.platform === "web") {
|
||||||
|
- return metro_transform_worker_1.default.transform(config, projectRoot, filename, Buffer.from(`require('${config.nativewind.outputPath}');`, "utf8"), options);
|
||||||
|
+ return metro_transform_worker_1.default.transform(config, projectRoot, filename, Buffer.from(`require('${config.nativewind.outputPath.replace(/\\/g, '\\\\')}');`, "utf8"), options);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data = Buffer.from(config.nativewind.rawOutput, "utf8");
|
2445
pnpm-lock.yaml
generated
2445
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user