mirror of
https://github.com/movie-web/native-app.git
synced 2025-09-13 18:13:25 +00:00
upgrade to v4
This commit is contained in:
@@ -1,26 +1,19 @@
|
||||
import { Tabs } from 'expo-router';
|
||||
import { NativeWindStyleSheet } from 'nativewind';
|
||||
|
||||
import TabBarIcon from '../../components/TabBarIcon';
|
||||
import { globalStyles } from '../../styles/global';
|
||||
import useTailwind from '../hooks/useTailwind';
|
||||
|
||||
NativeWindStyleSheet.setOutput({
|
||||
default: 'native',
|
||||
});
|
||||
import TabBarIcon from '../components/TabBarIcon';
|
||||
import Colors from '../constants/Colors';
|
||||
|
||||
export default function TabLayout() {
|
||||
const { colors } = useTailwind();
|
||||
return (
|
||||
<Tabs
|
||||
sceneContainerStyle={{
|
||||
backgroundColor: '#000',
|
||||
backgroundColor: Colors.background,
|
||||
}}
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: colors.purple[100],
|
||||
tabBarActiveTintColor: Colors.primary[100],
|
||||
tabBarStyle: {
|
||||
backgroundColor: colors.shade[700],
|
||||
backgroundColor: Colors.secondary[700],
|
||||
borderTopColor: 'transparent',
|
||||
borderTopRightRadius: 20,
|
||||
borderTopLeftRadius: 20,
|
||||
@@ -34,7 +27,6 @@ export default function TabLayout() {
|
||||
{
|
||||
marginTop: 2,
|
||||
},
|
||||
globalStyles.fOpenSansMedium,
|
||||
],
|
||||
}}
|
||||
>
|
||||
@@ -61,25 +53,9 @@ export default function TabLayout() {
|
||||
options={{
|
||||
title: 'Search',
|
||||
tabBarLabel: '',
|
||||
tabBarLabelStyle: {
|
||||
display: 'none',
|
||||
},
|
||||
tabBarIconStyle: {},
|
||||
tabBarIcon: () => (
|
||||
<TabBarIcon
|
||||
style={{
|
||||
position: 'relative',
|
||||
top: -1,
|
||||
backgroundColor: colors.purple[400],
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
aspectRatio: 1,
|
||||
borderRadius: 100,
|
||||
textAlign: 'center',
|
||||
textAlignVertical: 'center',
|
||||
height: 56,
|
||||
}}
|
||||
className=" bg-primary-400 flex aspect-[1/1] h-14 items-center justify-center rounded-full text-center text-2xl text-white"
|
||||
name="search"
|
||||
color="#FFF"
|
||||
/>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import ScreenLayout from '../../components/layout/ScreenLayout';
|
||||
import ScreenLayout from '../components/layout/ScreenLayout';
|
||||
|
||||
export default function AboutScreen() {
|
||||
return (
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import ScreenLayout from '../../components/layout/ScreenLayout';
|
||||
import ScreenLayout from '../components/layout/ScreenLayout';
|
||||
|
||||
export default function AccountScreen() {
|
||||
return (
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import ScreenLayout from '../../components/layout/ScreenLayout';
|
||||
import ScreenLayout from '../components/layout/ScreenLayout';
|
||||
|
||||
export default function HomeScreen() {
|
||||
return (
|
||||
|
@@ -3,11 +3,9 @@ import { useFocusEffect } from 'expo-router';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { TextInput } from 'react-native-gesture-handler';
|
||||
|
||||
import useTailwind from '../../hooks/useTailwind';
|
||||
import Colors from '../../constants/Colors';
|
||||
|
||||
export default function Searchbar() {
|
||||
const { colors } = useTailwind();
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
|
||||
@@ -25,9 +23,9 @@ export default function Searchbar() {
|
||||
);
|
||||
|
||||
return (
|
||||
<View className="mb-6 mt-4 flex-row items-center rounded-full border">
|
||||
<View className="border-primary-400 focus-within:border-primary-300 mb-6 mt-4 flex-row items-center rounded-full border">
|
||||
<View className="ml-1 w-12 items-center justify-center">
|
||||
<FontAwesome5 name="search" size={18} color={colors.shade[200]} />
|
||||
<FontAwesome5 name="search" size={18} color={Colors.secondary[200]} />
|
||||
</View>
|
||||
<TextInput
|
||||
value={keyword}
|
||||
@@ -35,8 +33,8 @@ export default function Searchbar() {
|
||||
onChangeText={(text) => setKeyword(text)}
|
||||
ref={inputRef}
|
||||
placeholder="What are you looking for?"
|
||||
placeholderTextColor={colors.shade[200]}
|
||||
className="w-full rounded-3xl py-3 pr-5 text-white"
|
||||
placeholderTextColor={Colors.secondary[200]}
|
||||
className="w-full rounded-3xl py-3 pr-5 text-white focus-visible:outline-none"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { ScrollView, Text, View } from 'react-native';
|
||||
|
||||
import Searchbar from './Searchbar';
|
||||
import Item from '../../../components/item/item';
|
||||
import ScreenLayout from '../../../components/layout/ScreenLayout';
|
||||
import ScreenLayout from '../../components/layout/ScreenLayout';
|
||||
import Item from '../../components/item/item';
|
||||
|
||||
export default function SearchScreen() {
|
||||
return (
|
||||
@@ -10,7 +10,7 @@ export default function SearchScreen() {
|
||||
<ScreenLayout
|
||||
title={
|
||||
<View className="flex-row items-center">
|
||||
<Text className="text-2xl font-bold">Search</Text>
|
||||
<Text className="text-2xl font-bold text-white">Search</Text>
|
||||
</View>
|
||||
}
|
||||
subtitle="Looking for something?"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import ScreenLayout from '../../components/layout/ScreenLayout';
|
||||
import ScreenLayout from '../components/layout/ScreenLayout';
|
||||
|
||||
export default function SettingsScreen() {
|
||||
return (
|
||||
|
@@ -10,8 +10,9 @@ import { SplashScreen, Stack } from 'expo-router';
|
||||
import { useEffect } from 'react';
|
||||
import { useColorScheme } from 'react-native';
|
||||
|
||||
import useTailwind from './hooks/useTailwind';
|
||||
import '../styles/global.css';
|
||||
import Colors from './constants/Colors';
|
||||
|
||||
import './styles/global.css';
|
||||
|
||||
export {
|
||||
// Catch any errors thrown by the Layout component.
|
||||
@@ -58,7 +59,6 @@ export default function RootLayout() {
|
||||
|
||||
function RootLayoutNav() {
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors } = useTailwind();
|
||||
|
||||
return (
|
||||
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||
@@ -67,7 +67,7 @@ function RootLayoutNav() {
|
||||
gestureEnabled: true,
|
||||
headerShown: false,
|
||||
contentStyle: {
|
||||
backgroundColor: colors.shade[900],
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
27
apps/mobile/app/components/ExternalLink.tsx
Normal file
27
apps/mobile/app/components/ExternalLink.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Link } from 'expo-router';
|
||||
import * as WebBrowser from 'expo-web-browser';
|
||||
import React from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
export function ExternalLink(
|
||||
props: Omit<React.ComponentProps<typeof Link>, 'href'> & { href: string },
|
||||
) {
|
||||
return (
|
||||
<Link
|
||||
hrefAttrs={{
|
||||
// On web, launch the link in a new tab.
|
||||
target: '_blank',
|
||||
}}
|
||||
{...props}
|
||||
href={props.href}
|
||||
onPress={(e) => {
|
||||
if (Platform.OS !== 'web') {
|
||||
// Prevent the default behavior of linking to the default browser on native.
|
||||
e.preventDefault();
|
||||
// Open the link in an in-app browser.
|
||||
WebBrowser.openBrowserAsync(props.href as string);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
16
apps/mobile/app/components/TabBarIcon.tsx
Normal file
16
apps/mobile/app/components/TabBarIcon.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
25
apps/mobile/app/components/item/item.tsx
Normal file
25
apps/mobile/app/components/item/item.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Image, Text, View } from 'react-native';
|
||||
|
||||
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 text-white">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>
|
||||
);
|
||||
}
|
20
apps/mobile/app/components/layout/ScreenLayout.tsx
Normal file
20
apps/mobile/app/components/layout/ScreenLayout.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
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 text-white">{title}</Text>
|
||||
)}
|
||||
{typeof title !== 'string' && title}
|
||||
<Text className="mt-1 text-sm font-bold text-white">{subtitle}</Text>
|
||||
<View className="py-3">{children}</View>
|
||||
</View>
|
||||
);
|
||||
}
|
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
apps/mobile/app/constants/General.ts
Normal file
1
apps/mobile/app/constants/General.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const TMDB_POSTER_PATH = `https://image.tmdb.org/t/p`;
|
@@ -1,16 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import resolveConfig from 'tailwindcss/resolveConfig';
|
||||
|
||||
import tailwindConfig from '../../tailwind.config';
|
||||
|
||||
const useTailwind = () => {
|
||||
const tailwind = useMemo(() => resolveConfig(tailwindConfig), []);
|
||||
console.log(tailwind);
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
colors: tailwind.theme.colors as typeof tailwindConfig.theme.extend.colors,
|
||||
};
|
||||
};
|
||||
|
||||
export default useTailwind;
|
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;
|
Reference in New Issue
Block a user