mirror of
https://github.com/movie-web/native-app.git
synced 2025-09-13 10:23:24 +00:00
@@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": true
|
"singleQuote": true,
|
||||||
|
"endOfLine": "auto"
|
||||||
}
|
}
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -6,6 +6,6 @@
|
|||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,12 @@ module.exports = {
|
|||||||
'react/react-in-jsx-scope': 'off',
|
'react/react-in-jsx-scope': 'off',
|
||||||
'react/require-default-props': 'off',
|
'react/require-default-props': 'off',
|
||||||
'react/destructuring-assignment': 'off',
|
'react/destructuring-assignment': 'off',
|
||||||
|
'prettier/prettier': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
endOfLine: 'auto',
|
||||||
|
},
|
||||||
|
],
|
||||||
'react/jsx-filename-extension': [
|
'react/jsx-filename-extension': [
|
||||||
'error',
|
'error',
|
||||||
{ extensions: ['.js', '.tsx', '.jsx'] },
|
{ extensions: ['.js', '.tsx', '.jsx'] },
|
||||||
|
@@ -1,54 +1,102 @@
|
|||||||
import FontAwesome from '@expo/vector-icons/FontAwesome';
|
import { Tabs } from 'expo-router';
|
||||||
import { Link, Tabs } from 'expo-router';
|
|
||||||
import { Pressable, useColorScheme } from 'react-native';
|
|
||||||
|
|
||||||
import Colors from '../../constants/Colors';
|
import Colors from '../../constants/Colors';
|
||||||
|
import TabBarIcon from '../../components/TabBarIcon';
|
||||||
/**
|
import { globalStyles } from '../../styles/global';
|
||||||
* You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
|
|
||||||
*/
|
|
||||||
function TabBarIcon(props: {
|
|
||||||
name: React.ComponentProps<typeof FontAwesome>['name'];
|
|
||||||
color: string;
|
|
||||||
}) {
|
|
||||||
return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
const colorScheme = useColorScheme();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
|
sceneContainerStyle={{
|
||||||
|
backgroundColor: '#000',
|
||||||
|
}}
|
||||||
screenOptions={{
|
screenOptions={{
|
||||||
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
|
headerShown: false,
|
||||||
|
tabBarActiveTintColor: Colors.dark.purple100,
|
||||||
|
tabBarStyle: {
|
||||||
|
backgroundColor: Colors.dark.shade700,
|
||||||
|
borderTopColor: 'transparent',
|
||||||
|
borderTopRightRadius: 20,
|
||||||
|
borderTopLeftRadius: 20,
|
||||||
|
height: 80,
|
||||||
|
},
|
||||||
|
tabBarItemStyle: {
|
||||||
|
paddingVertical: 18,
|
||||||
|
height: 82,
|
||||||
|
},
|
||||||
|
tabBarLabelStyle: [
|
||||||
|
{
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
globalStyles.fOpenSansMedium,
|
||||||
|
],
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="index"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: 'Tab One',
|
title: 'Home',
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
tabBarIcon: ({ focused }) => (
|
||||||
headerRight: () => (
|
<TabBarIcon name="home" focused={focused} />
|
||||||
<Link href="/modal" asChild>
|
|
||||||
<Pressable>
|
|
||||||
{({ pressed }) => (
|
|
||||||
<FontAwesome
|
|
||||||
name="info-circle"
|
|
||||||
size={25}
|
|
||||||
color={Colors[colorScheme ?? 'light'].text}
|
|
||||||
style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Pressable>
|
|
||||||
</Link>
|
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="two"
|
name="about"
|
||||||
options={{
|
options={{
|
||||||
title: 'Tab Two',
|
title: 'About',
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
tabBarIcon: ({ focused }) => (
|
||||||
|
<TabBarIcon name="info-circle" focused={focused} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="search"
|
||||||
|
options={{
|
||||||
|
title: 'Search',
|
||||||
|
tabBarLabel: '',
|
||||||
|
tabBarShowLabel: false,
|
||||||
|
tabBarLabelStyle: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
tabBarIconStyle: {},
|
||||||
|
tabBarIcon: () => (
|
||||||
|
<TabBarIcon
|
||||||
|
style={{
|
||||||
|
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"
|
||||||
|
color="#FFF"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="settings"
|
||||||
|
options={{
|
||||||
|
title: 'Settings',
|
||||||
|
tabBarIcon: ({ focused }) => (
|
||||||
|
<TabBarIcon name="cog" focused={focused} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="account"
|
||||||
|
options={{
|
||||||
|
title: 'Account',
|
||||||
|
tabBarIcon: ({ focused }) => (
|
||||||
|
<TabBarIcon name="user" focused={focused} />
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
36
apps/mobile/app/(tabs)/about.tsx
Normal file
36
apps/mobile/app/(tabs)/about.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
import ScreenLayout from '../../components/layout/screenLayout';
|
||||||
|
import { globalStyles } from '../../styles/global';
|
||||||
|
import { RegularText } from '../../components/Styled';
|
||||||
|
|
||||||
|
export default function AboutScreen() {
|
||||||
|
return (
|
||||||
|
<ScreenLayout
|
||||||
|
title="About"
|
||||||
|
subtitle="What is movie-web and how content is served?"
|
||||||
|
>
|
||||||
|
<RegularText style={globalStyles.textWhite}>
|
||||||
|
No content is served from movie-web directly and movie web does not host
|
||||||
|
anything.
|
||||||
|
</RegularText>
|
||||||
|
</ScreenLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
marginVertical: 30,
|
||||||
|
height: 1,
|
||||||
|
width: '80%',
|
||||||
|
},
|
||||||
|
});
|
18
apps/mobile/app/(tabs)/account.tsx
Normal file
18
apps/mobile/app/(tabs)/account.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { StyleSheet, Text } from 'react-native';
|
||||||
|
|
||||||
|
import { globalStyles } from '../../styles/global';
|
||||||
|
import ScreenLayout from '../../components/layout/screenLayout';
|
||||||
|
import { RegularText } from '../../components/Styled';
|
||||||
|
|
||||||
|
export default function AccountScreen() {
|
||||||
|
return (
|
||||||
|
<ScreenLayout
|
||||||
|
title="Account"
|
||||||
|
subtitle="Manage your movie web account from here"
|
||||||
|
>
|
||||||
|
<RegularText style={globalStyles.textWhite}>
|
||||||
|
Hey Bro! what are you up to?
|
||||||
|
</RegularText>
|
||||||
|
</ScreenLayout>
|
||||||
|
);
|
||||||
|
}
|
@@ -1,35 +1,13 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
import { RegularText } from '../../components/Styled';
|
||||||
|
import ScreenLayout from '../../components/layout/screenLayout';
|
||||||
|
import { globalStyles } from '../../styles/global';
|
||||||
|
|
||||||
import EditScreenInfo from '../../components/EditScreenInfo';
|
export default function HomeScreen() {
|
||||||
import { Text, View } from '../../components/Themed';
|
|
||||||
|
|
||||||
export default function TabOneScreen() {
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<ScreenLayout title="Home" subtitle="This is where all magic happens">
|
||||||
<Text style={styles.title}>Tab One</Text>
|
<RegularText style={globalStyles.textWhite}>
|
||||||
<View
|
Movies will be listed here
|
||||||
style={styles.separator}
|
</RegularText>
|
||||||
lightColor="#eee"
|
</ScreenLayout>
|
||||||
darkColor="rgba(255,255,255,0.1)"
|
|
||||||
/>
|
|
||||||
<EditScreenInfo path="app/(tabs)/index.tsx" />
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
marginVertical: 30,
|
|
||||||
height: 1,
|
|
||||||
width: '80%',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
64
apps/mobile/app/(tabs)/search/Searchbar.tsx
Normal file
64
apps/mobile/app/(tabs)/search/Searchbar.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { FontAwesome5 } from '@expo/vector-icons';
|
||||||
|
import { useCallback, useRef, useState } from 'react';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
import { TextInput } from 'react-native-gesture-handler';
|
||||||
|
import { globalStyles } from '../../../styles/global';
|
||||||
|
import Colors from '../../../constants/Colors';
|
||||||
|
import { useFocusEffect } from 'expo-router';
|
||||||
|
|
||||||
|
export default function Searchbar() {
|
||||||
|
const [keyword, setKeyword] = useState('');
|
||||||
|
const inputRef = useRef<TextInput>(null);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
// When the screen is focused
|
||||||
|
const focus = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
inputRef?.current?.focus();
|
||||||
|
}, 20);
|
||||||
|
};
|
||||||
|
focus();
|
||||||
|
return focus; // cleanup
|
||||||
|
}, []),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
...globalStyles.flexRow,
|
||||||
|
...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>
|
||||||
|
<TextInput
|
||||||
|
value={keyword}
|
||||||
|
autoFocus={true}
|
||||||
|
onChangeText={(text) => setKeyword(text)}
|
||||||
|
ref={inputRef}
|
||||||
|
placeholder="What are you looking for?"
|
||||||
|
placeholderTextColor={Colors.dark.shade200}
|
||||||
|
style={[
|
||||||
|
globalStyles.input,
|
||||||
|
globalStyles.fOpenSansRegular,
|
||||||
|
{
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
></TextInput>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
41
apps/mobile/app/(tabs)/search/_layout.tsx
Normal file
41
apps/mobile/app/(tabs)/search/_layout.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Dimensions, ScrollView, View } from 'react-native';
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
export default function SearchScreen() {
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
<ScreenLayout
|
||||||
|
title={
|
||||||
|
<View
|
||||||
|
style={{ ...globalStyles.flexRow, ...globalStyles.itemsCenter }}
|
||||||
|
>
|
||||||
|
<BoldText style={globalStyles.sectionTitle}>Search</BoldText>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
subtitle="Looking for something?"
|
||||||
|
>
|
||||||
|
<Searchbar />
|
||||||
|
<View style={styles.items}>
|
||||||
|
<View style={styles.itemOuter}>
|
||||||
|
<Item />
|
||||||
|
</View>
|
||||||
|
<View style={styles.itemOuter}>
|
||||||
|
<Item />
|
||||||
|
</View>
|
||||||
|
<View style={styles.itemOuter}>
|
||||||
|
<Item />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ScreenLayout>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
19
apps/mobile/app/(tabs)/search/styles.tsx
Normal file
19
apps/mobile/app/(tabs)/search/styles.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
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;
|
14
apps/mobile/app/(tabs)/settings.tsx
Normal file
14
apps/mobile/app/(tabs)/settings.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { RegularText } from '../../components/Styled';
|
||||||
|
import ScreenLayout from '../../components/layout/screenLayout';
|
||||||
|
import { globalStyles } from '../../styles/global';
|
||||||
|
import { StyleSheet, Text } from 'react-native';
|
||||||
|
|
||||||
|
export default function SettingsScreen() {
|
||||||
|
return (
|
||||||
|
<ScreenLayout title="Settings" subtitle="Need to change something?">
|
||||||
|
<RegularText style={globalStyles.textWhite}>
|
||||||
|
Settings would be listed in here. Coming soon
|
||||||
|
</RegularText>
|
||||||
|
</ScreenLayout>
|
||||||
|
);
|
||||||
|
}
|
@@ -1,35 +0,0 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
|
||||||
|
|
||||||
import EditScreenInfo from '../../components/EditScreenInfo';
|
|
||||||
import { Text, View } from '../../components/Themed';
|
|
||||||
|
|
||||||
export default function TabTwoScreen() {
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
<Text style={styles.title}>Tab Two</Text>
|
|
||||||
<View
|
|
||||||
style={styles.separator}
|
|
||||||
lightColor="#eee"
|
|
||||||
darkColor="rgba(255,255,255,0.1)"
|
|
||||||
/>
|
|
||||||
<EditScreenInfo path="app/(tabs)/two.tsx" />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
marginVertical: 30,
|
|
||||||
height: 1,
|
|
||||||
width: '80%',
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,17 +1,18 @@
|
|||||||
import { Link, Stack } from 'expo-router';
|
import { Link, Stack } from 'expo-router';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
import { BoldText, RegularText } from '../components/Styled';
|
||||||
import { Text, View } from '../components/Themed';
|
|
||||||
|
|
||||||
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 style={styles.container}>
|
||||||
<Text style={styles.title}>This screen doesn't exist.</Text>
|
<BoldText style={styles.title}>
|
||||||
|
This screen doesn't exist.
|
||||||
|
</BoldText>
|
||||||
|
|
||||||
<Link href="/" style={styles.link}>
|
<Link href="/" style={styles.link}>
|
||||||
<Text style={styles.linkText}>Go to home screen!</Text>
|
<RegularText style={styles.linkText}>Go to home screen!</RegularText>
|
||||||
</Link>
|
</Link>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
|
@@ -9,6 +9,8 @@ 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';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// Catch any errors thrown by the Layout component.
|
// Catch any errors thrown by the Layout component.
|
||||||
ErrorBoundary,
|
ErrorBoundary,
|
||||||
@@ -26,7 +28,12 @@ SplashScreen.preventAutoHideAsync();
|
|||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
const [loaded, error] = useFonts({
|
const [loaded, error] = useFonts({
|
||||||
// eslint-disable-next-line global-require
|
// eslint-disable-next-line global-require
|
||||||
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
|
OpenSansRegular: require('../assets/fonts/OpenSans-Regular.ttf'),
|
||||||
|
OpenSansLight: require('../assets/fonts/OpenSans-Light.ttf'),
|
||||||
|
OpenSansMedium: require('../assets/fonts/OpenSans-Medium.ttf'),
|
||||||
|
OpenSansBold: require('../assets/fonts/OpenSans-Bold.ttf'),
|
||||||
|
OpenSansSemiBold: require('../assets/fonts/OpenSans-SemiBold.ttf'),
|
||||||
|
OpenSansExtra: require('../assets/fonts/OpenSans-ExtraBold.ttf'),
|
||||||
...FontAwesome.font,
|
...FontAwesome.font,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -53,7 +60,15 @@ function RootLayoutNav() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||||
<Stack>
|
<Stack
|
||||||
|
screenOptions={{
|
||||||
|
gestureEnabled: true,
|
||||||
|
headerShown: false,
|
||||||
|
contentStyle: {
|
||||||
|
backgroundColor: Colors.dark.shade900,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
|
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@@ -1,19 +1,13 @@
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import { Platform, StyleSheet } from 'react-native';
|
import { Platform, StyleSheet, View } from 'react-native';
|
||||||
|
import { BoldText, RegularText } from '../components/Styled';
|
||||||
import EditScreenInfo from '../components/EditScreenInfo';
|
|
||||||
import { Text, View } from '../components/Themed';
|
|
||||||
|
|
||||||
export default function ModalScreen() {
|
export default function ModalScreen() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={styles.title}>Modal</Text>
|
<BoldText style={styles.title}>Modal</BoldText>
|
||||||
<View
|
<View style={styles.separator} />
|
||||||
style={styles.separator}
|
<RegularText>Modal?!</RegularText>
|
||||||
lightColor="#eee"
|
|
||||||
darkColor="rgba(255,255,255,0.1)"
|
|
||||||
/>
|
|
||||||
<EditScreenInfo path="app/modal.tsx" />
|
|
||||||
|
|
||||||
{/* Use a light status bar on iOS to account for the black space above the modal */}
|
{/* Use a light status bar on iOS to account for the black space above the modal */}
|
||||||
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
|
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
|
||||||
|
BIN
apps/mobile/assets/fonts/OpenSans-Bold.ttf
Normal file
BIN
apps/mobile/assets/fonts/OpenSans-Bold.ttf
Normal file
Binary file not shown.
BIN
apps/mobile/assets/fonts/OpenSans-ExtraBold.ttf
Normal file
BIN
apps/mobile/assets/fonts/OpenSans-ExtraBold.ttf
Normal file
Binary file not shown.
BIN
apps/mobile/assets/fonts/OpenSans-Light.ttf
Normal file
BIN
apps/mobile/assets/fonts/OpenSans-Light.ttf
Normal file
Binary file not shown.
BIN
apps/mobile/assets/fonts/OpenSans-Medium.ttf
Normal file
BIN
apps/mobile/assets/fonts/OpenSans-Medium.ttf
Normal file
Binary file not shown.
BIN
apps/mobile/assets/fonts/OpenSans-Regular.ttf
Normal file
BIN
apps/mobile/assets/fonts/OpenSans-Regular.ttf
Normal file
Binary file not shown.
BIN
apps/mobile/assets/fonts/OpenSans-SemiBold.ttf
Normal file
BIN
apps/mobile/assets/fonts/OpenSans-SemiBold.ttf
Normal file
Binary file not shown.
@@ -1,82 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { StyleSheet } from 'react-native';
|
|
||||||
|
|
||||||
import { ExternalLink } from './ExternalLink';
|
|
||||||
import { MonoText } from './StyledText';
|
|
||||||
import { Text, View } from './Themed';
|
|
||||||
import Colors from '../constants/Colors';
|
|
||||||
|
|
||||||
export default function EditScreenInfo({ path }: { path: string }) {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<View style={styles.getStartedContainer}>
|
|
||||||
<Text
|
|
||||||
style={styles.getStartedText}
|
|
||||||
lightColor="rgba(0,0,0,0.8)"
|
|
||||||
darkColor="rgba(255,255,255,0.8)"
|
|
||||||
>
|
|
||||||
Open up the code for this screen:
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={[styles.codeHighlightContainer, styles.homeScreenFilename]}
|
|
||||||
darkColor="rgba(255,255,255,0.05)"
|
|
||||||
lightColor="rgba(0,0,0,0.05)"
|
|
||||||
>
|
|
||||||
<MonoText>{path}</MonoText>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text
|
|
||||||
style={styles.getStartedText}
|
|
||||||
lightColor="rgba(0,0,0,0.8)"
|
|
||||||
darkColor="rgba(255,255,255,0.8)"
|
|
||||||
>
|
|
||||||
Change any of the text, save the file, and your app will automatically
|
|
||||||
update.
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.helpContainer}>
|
|
||||||
<ExternalLink
|
|
||||||
style={styles.helpLink}
|
|
||||||
href="https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet"
|
|
||||||
>
|
|
||||||
<Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
|
|
||||||
Tap here if your app doesn't automatically update after making
|
|
||||||
changes
|
|
||||||
</Text>
|
|
||||||
</ExternalLink>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
getStartedContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
marginHorizontal: 50,
|
|
||||||
},
|
|
||||||
homeScreenFilename: {
|
|
||||||
marginVertical: 7,
|
|
||||||
},
|
|
||||||
codeHighlightContainer: {
|
|
||||||
borderRadius: 3,
|
|
||||||
paddingHorizontal: 4,
|
|
||||||
},
|
|
||||||
getStartedText: {
|
|
||||||
fontSize: 17,
|
|
||||||
lineHeight: 24,
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
helpContainer: {
|
|
||||||
marginTop: 15,
|
|
||||||
marginHorizontal: 20,
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
helpLink: {
|
|
||||||
paddingVertical: 15,
|
|
||||||
},
|
|
||||||
helpLinkText: {
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
});
|
|
44
apps/mobile/components/Styled.tsx
Normal file
44
apps/mobile/components/Styled.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
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,5 +0,0 @@
|
|||||||
import { Text, TextProps } from './Themed';
|
|
||||||
|
|
||||||
export function MonoText(props: TextProps) {
|
|
||||||
return <Text {...props} style={[props.style, { fontFamily: 'SpaceMono' }]} />;
|
|
||||||
}
|
|
21
apps/mobile/components/TabBarIcon.tsx
Normal file
21
apps/mobile/components/TabBarIcon.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
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,50 +0,0 @@
|
|||||||
/**
|
|
||||||
* Learn more about Light and Dark modes:
|
|
||||||
* https://docs.expo.io/guides/color-schemes/
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
Text as DefaultText,
|
|
||||||
View as DefaultView,
|
|
||||||
useColorScheme,
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
import Colors from '../constants/Colors';
|
|
||||||
|
|
||||||
type ThemeProps = {
|
|
||||||
lightColor?: string;
|
|
||||||
darkColor?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TextProps = ThemeProps & DefaultText['props'];
|
|
||||||
export type ViewProps = ThemeProps & DefaultView['props'];
|
|
||||||
|
|
||||||
export function useThemeColor(
|
|
||||||
props: { light?: string; dark?: string },
|
|
||||||
colorName: keyof typeof Colors.light & keyof typeof Colors.dark,
|
|
||||||
) {
|
|
||||||
const theme = useColorScheme() ?? 'light';
|
|
||||||
const colorFromProps = props[theme];
|
|
||||||
|
|
||||||
if (colorFromProps) {
|
|
||||||
return colorFromProps;
|
|
||||||
}
|
|
||||||
return Colors[theme][colorName];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Text(props: TextProps) {
|
|
||||||
const { style, lightColor, darkColor, ...otherProps } = props;
|
|
||||||
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
|
|
||||||
|
|
||||||
return <DefaultText style={[{ color }, style]} {...otherProps} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function View(props: ViewProps) {
|
|
||||||
const { style, lightColor, darkColor, ...otherProps } = props;
|
|
||||||
const backgroundColor = useThemeColor(
|
|
||||||
{ light: lightColor, dark: darkColor },
|
|
||||||
'background',
|
|
||||||
);
|
|
||||||
|
|
||||||
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
|
|
||||||
}
|
|
31
apps/mobile/components/item/item.tsx
Normal file
31
apps/mobile/components/item/item.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
31
apps/mobile/components/item/styles.tsx
Normal file
31
apps/mobile/components/item/styles.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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;
|
31
apps/mobile/components/layout/screenLayout.tsx
Normal file
31
apps/mobile/components/layout/screenLayout.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
10
apps/mobile/components/layout/styles.tsx
Normal file
10
apps/mobile/components/layout/styles.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Dimensions, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
minHeight: Dimensions.get('window').height,
|
||||||
|
},
|
||||||
|
children: {
|
||||||
|
paddingVertical: 12,
|
||||||
|
},
|
||||||
|
});
|
@@ -15,5 +15,13 @@ export default {
|
|||||||
tint: tintColorDark,
|
tint: tintColorDark,
|
||||||
tabIconDefault: '#ccc',
|
tabIconDefault: '#ccc',
|
||||||
tabIconSelected: tintColorDark,
|
tabIconSelected: tintColorDark,
|
||||||
|
purple100: '#C082FF',
|
||||||
|
purple300: '#8D44D6',
|
||||||
|
purple400: '#7831BF',
|
||||||
|
shade50: '#676790',
|
||||||
|
shade200: '#3F3F60',
|
||||||
|
shade300: '#32324F',
|
||||||
|
shade700: '#131322',
|
||||||
|
shade900: '#0A0A12',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
1
apps/mobile/constants/General.ts
Normal file
1
apps/mobile/constants/General.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const TMDB_POSTER_PATH = `https://image.tmdb.org/t/p`;
|
75
apps/mobile/styles/global.tsx
Normal file
75
apps/mobile/styles/global.tsx
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
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,
|
||||||
|
},
|
||||||
|
});
|
Reference in New Issue
Block a user