parent
7d3704bb4d
commit
c71bd5462a
@ -0,0 +1,37 @@ |
|||||||
|
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files |
||||||
|
|
||||||
|
# dependencies |
||||||
|
node_modules/ |
||||||
|
|
||||||
|
# Expo |
||||||
|
.expo/ |
||||||
|
dist/ |
||||||
|
web-build/ |
||||||
|
expo-env.d.ts |
||||||
|
|
||||||
|
# Native |
||||||
|
.kotlin/ |
||||||
|
*.orig.* |
||||||
|
*.jks |
||||||
|
*.p8 |
||||||
|
*.p12 |
||||||
|
*.key |
||||||
|
*.mobileprovision |
||||||
|
|
||||||
|
# Metro |
||||||
|
.metro-health-check* |
||||||
|
|
||||||
|
# debug |
||||||
|
npm-debug.* |
||||||
|
yarn-debug.* |
||||||
|
yarn-error.* |
||||||
|
|
||||||
|
# macOS |
||||||
|
.DS_Store |
||||||
|
*.pem |
||||||
|
|
||||||
|
# local env files |
||||||
|
.env*.local |
||||||
|
|
||||||
|
# typescript |
||||||
|
*.tsbuildinfo |
@ -0,0 +1,38 @@ |
|||||||
|
{ |
||||||
|
"expo": { |
||||||
|
"name": "my-expo-sample", |
||||||
|
"slug": "my-expo-sample", |
||||||
|
"version": "1.0.0", |
||||||
|
"orientation": "portrait", |
||||||
|
"icon": "./assets/images/icon.png", |
||||||
|
"scheme": "myexposample", |
||||||
|
"userInterfaceStyle": "automatic", |
||||||
|
"newArchEnabled": true, |
||||||
|
"splash": { |
||||||
|
"image": "./assets/images/splash-icon.png", |
||||||
|
"resizeMode": "contain", |
||||||
|
"backgroundColor": "#ffffff" |
||||||
|
}, |
||||||
|
"ios": { |
||||||
|
"supportsTablet": true |
||||||
|
}, |
||||||
|
"android": { |
||||||
|
"adaptiveIcon": { |
||||||
|
"foregroundImage": "./assets/images/adaptive-icon.png", |
||||||
|
"backgroundColor": "#ffffff" |
||||||
|
}, |
||||||
|
"edgeToEdgeEnabled": true |
||||||
|
}, |
||||||
|
"web": { |
||||||
|
"bundler": "metro", |
||||||
|
"output": "static", |
||||||
|
"favicon": "./assets/images/favicon.png" |
||||||
|
}, |
||||||
|
"plugins": [ |
||||||
|
"expo-router" |
||||||
|
], |
||||||
|
"experiments": { |
||||||
|
"typedRoutes": true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import FontAwesome from '@expo/vector-icons/FontAwesome'; |
||||||
|
import { Link, Tabs } from 'expo-router'; |
||||||
|
import { Pressable } from 'react-native'; |
||||||
|
|
||||||
|
import Colors from '@/constants/Colors'; |
||||||
|
import { useColorScheme } from '@/components/useColorScheme'; |
||||||
|
import { useClientOnlyValue } from '@/components/useClientOnlyValue'; |
||||||
|
|
||||||
|
// 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() { |
||||||
|
const colorScheme = useColorScheme(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<Tabs |
||||||
|
screenOptions={{ |
||||||
|
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint, |
||||||
|
// Disable the static render of the header on web
|
||||||
|
// to prevent a hydration error in React Navigation v6.
|
||||||
|
headerShown: useClientOnlyValue(false, true), |
||||||
|
}}> |
||||||
|
<Tabs.Screen |
||||||
|
name="index" |
||||||
|
options={{ |
||||||
|
title: 'Tab One', |
||||||
|
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />, |
||||||
|
headerRight: () => ( |
||||||
|
<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 |
||||||
|
name="two" |
||||||
|
options={{ |
||||||
|
title: 'Tab Two', |
||||||
|
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />, |
||||||
|
}} |
||||||
|
/> |
||||||
|
</Tabs> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
import { StyleSheet } from 'react-native'; |
||||||
|
|
||||||
|
import EditScreenInfo from '@/components/EditScreenInfo'; |
||||||
|
import { Text, View } from '@/components/Themed'; |
||||||
|
|
||||||
|
export default function TabOneScreen() { |
||||||
|
return ( |
||||||
|
<View style={styles.container}> |
||||||
|
<Text style={styles.title}>Tab One</Text> |
||||||
|
<View style={styles.separator} lightColor="#eee" 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%', |
||||||
|
}, |
||||||
|
}); |
@ -0,0 +1,31 @@ |
|||||||
|
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%', |
||||||
|
}, |
||||||
|
}); |
@ -0,0 +1,38 @@ |
|||||||
|
import { ScrollViewStyleReset } from 'expo-router/html'; |
||||||
|
|
||||||
|
// This file is web-only and used to configure the root HTML for every
|
||||||
|
// web page during static rendering.
|
||||||
|
// The contents of this function only run in Node.js environments and
|
||||||
|
// do not have access to the DOM or browser APIs.
|
||||||
|
export default function Root({ children }: { children: React.ReactNode }) { |
||||||
|
return ( |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charSet="utf-8" /> |
||||||
|
<meta httpEquiv="X-UA-Compatible" content="IE=edge" /> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> |
||||||
|
|
||||||
|
{/* |
||||||
|
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
|
||||||
|
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line. |
||||||
|
*/} |
||||||
|
<ScrollViewStyleReset /> |
||||||
|
|
||||||
|
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */} |
||||||
|
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} /> |
||||||
|
{/* Add any additional <head> elements that you want globally available on web... */} |
||||||
|
</head> |
||||||
|
<body>{children}</body> |
||||||
|
</html> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const responsiveBackground = ` |
||||||
|
body { |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
@media (prefers-color-scheme: dark) { |
||||||
|
body { |
||||||
|
background-color: #000; |
||||||
|
} |
||||||
|
}`;
|
@ -0,0 +1,40 @@ |
|||||||
|
import { Link, Stack } from 'expo-router'; |
||||||
|
import { StyleSheet } from 'react-native'; |
||||||
|
|
||||||
|
import { Text, View } from '@/components/Themed'; |
||||||
|
|
||||||
|
export default function NotFoundScreen() { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Stack.Screen options={{ title: 'Oops!' }} /> |
||||||
|
<View style={styles.container}> |
||||||
|
<Text style={styles.title}>This screen doesn't exist.</Text> |
||||||
|
|
||||||
|
<Link href="/" style={styles.link}> |
||||||
|
<Text style={styles.linkText}>Go to home screen!</Text> |
||||||
|
</Link> |
||||||
|
</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', |
||||||
|
}, |
||||||
|
}); |
@ -0,0 +1,59 @@ |
|||||||
|
import FontAwesome from '@expo/vector-icons/FontAwesome'; |
||||||
|
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; |
||||||
|
import { useFonts } from 'expo-font'; |
||||||
|
import { Stack } from 'expo-router'; |
||||||
|
import * as SplashScreen from 'expo-splash-screen'; |
||||||
|
import { useEffect } from 'react'; |
||||||
|
import 'react-native-reanimated'; |
||||||
|
|
||||||
|
import { useColorScheme } from '@/components/useColorScheme'; |
||||||
|
|
||||||
|
export { |
||||||
|
// Catch any errors thrown by the Layout component.
|
||||||
|
ErrorBoundary, |
||||||
|
} from 'expo-router'; |
||||||
|
|
||||||
|
export const unstable_settings = { |
||||||
|
// Ensure that reloading on `/modal` keeps a back button present.
|
||||||
|
initialRouteName: '(tabs)', |
||||||
|
}; |
||||||
|
|
||||||
|
// Prevent the splash screen from auto-hiding before asset loading is complete.
|
||||||
|
SplashScreen.preventAutoHideAsync(); |
||||||
|
|
||||||
|
export default function RootLayout() { |
||||||
|
const [loaded, error] = useFonts({ |
||||||
|
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), |
||||||
|
...FontAwesome.font, |
||||||
|
}); |
||||||
|
|
||||||
|
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
|
||||||
|
useEffect(() => { |
||||||
|
if (error) throw error; |
||||||
|
}, [error]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (loaded) { |
||||||
|
SplashScreen.hideAsync(); |
||||||
|
} |
||||||
|
}, [loaded]); |
||||||
|
|
||||||
|
if (!loaded) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return <RootLayoutNav />; |
||||||
|
} |
||||||
|
|
||||||
|
function RootLayoutNav() { |
||||||
|
const colorScheme = useColorScheme(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> |
||||||
|
<Stack> |
||||||
|
<Stack.Screen name="(tabs)" options={{ headerShown: false }} /> |
||||||
|
<Stack.Screen name="modal" options={{ presentation: 'modal' }} /> |
||||||
|
</Stack> |
||||||
|
</ThemeProvider> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
import { StatusBar } from 'expo-status-bar'; |
||||||
|
import { Platform, StyleSheet } from 'react-native'; |
||||||
|
|
||||||
|
import EditScreenInfo from '@/components/EditScreenInfo'; |
||||||
|
import { Text, View } from '@/components/Themed'; |
||||||
|
|
||||||
|
export default function ModalScreen() { |
||||||
|
return ( |
||||||
|
<View style={styles.container}> |
||||||
|
<Text style={styles.title}>Modal</Text> |
||||||
|
<View style={styles.separator} 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 */} |
||||||
|
<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%', |
||||||
|
}, |
||||||
|
}); |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 17 KiB |
@ -0,0 +1,77 @@ |
|||||||
|
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', |
||||||
|
}, |
||||||
|
}); |
@ -0,0 +1,25 @@ |
|||||||
|
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 |
||||||
|
target="_blank" |
||||||
|
{...props} |
||||||
|
// @ts-expect-error: External URLs are not typed.
|
||||||
|
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); |
||||||
|
} |
||||||
|
}} |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
import { Text, TextProps } from './Themed'; |
||||||
|
|
||||||
|
export function MonoText(props: TextProps) { |
||||||
|
return <Text {...props} style={[props.style, { fontFamily: 'SpaceMono' }]} />; |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
/** |
||||||
|
* Learn more about Light and Dark modes: |
||||||
|
* https://docs.expo.io/guides/color-schemes/
|
||||||
|
*/ |
||||||
|
|
||||||
|
import { Text as DefaultText, View as DefaultView } from 'react-native'; |
||||||
|
|
||||||
|
import Colors from '@/constants/Colors'; |
||||||
|
import { useColorScheme } from './useColorScheme'; |
||||||
|
|
||||||
|
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; |
||||||
|
} else { |
||||||
|
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} />; |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
import * as React from 'react'; |
||||||
|
import renderer from 'react-test-renderer'; |
||||||
|
|
||||||
|
import { MonoText } from '../StyledText'; |
||||||
|
|
||||||
|
it(`renders correctly`, () => { |
||||||
|
const tree = renderer.create(<MonoText>Snapshot test!</MonoText>).toJSON(); |
||||||
|
|
||||||
|
expect(tree).toMatchSnapshot(); |
||||||
|
}); |
@ -0,0 +1,4 @@ |
|||||||
|
// This function is web-only as native doesn't currently support server (or build-time) rendering.
|
||||||
|
export function useClientOnlyValue<S, C>(server: S, client: C): S | C { |
||||||
|
return client; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
import React from 'react'; |
||||||
|
|
||||||
|
// `useEffect` is not invoked during server rendering, meaning
|
||||||
|
// we can use this to determine if we're on the server or not.
|
||||||
|
export function useClientOnlyValue<S, C>(server: S, client: C): S | C { |
||||||
|
const [value, setValue] = React.useState<S | C>(server); |
||||||
|
React.useEffect(() => { |
||||||
|
setValue(client); |
||||||
|
}, [client]); |
||||||
|
|
||||||
|
return value; |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
export { useColorScheme } from 'react-native'; |
@ -0,0 +1,8 @@ |
|||||||
|
// NOTE: The default React Native styling doesn't support server rendering.
|
||||||
|
// Server rendered styles should not change between the first render of the HTML
|
||||||
|
// and the first render on the client. Typically, web developers will use CSS media queries
|
||||||
|
// to render different styles on the client and server, these aren't directly supported in React Native
|
||||||
|
// but can be achieved using a styling library like Nativewind.
|
||||||
|
export function useColorScheme() { |
||||||
|
return 'light'; |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
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, |
||||||
|
}, |
||||||
|
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,43 @@ |
|||||||
|
{ |
||||||
|
"name": "my-expo-sample", |
||||||
|
"main": "expo-router/entry", |
||||||
|
"version": "1.0.0", |
||||||
|
"scripts": { |
||||||
|
"start": "expo start", |
||||||
|
"android": "expo start --android", |
||||||
|
"ios": "expo start --ios", |
||||||
|
"web": "expo start --web", |
||||||
|
"test": "jest --watchAll" |
||||||
|
}, |
||||||
|
"jest": { |
||||||
|
"preset": "jest-expo" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@expo/vector-icons": "^14.1.0", |
||||||
|
"@react-navigation/native": "^7.1.6", |
||||||
|
"expo": "~53.0.15", |
||||||
|
"expo-font": "~13.3.2", |
||||||
|
"expo-linking": "~7.1.6", |
||||||
|
"expo-router": "~5.1.2", |
||||||
|
"expo-splash-screen": "~0.30.9", |
||||||
|
"expo-status-bar": "~2.2.3", |
||||||
|
"expo-system-ui": "~5.0.9", |
||||||
|
"expo-web-browser": "~14.2.0", |
||||||
|
"react": "19.0.0", |
||||||
|
"react-dom": "19.0.0", |
||||||
|
"react-native": "0.79.4", |
||||||
|
"react-native-reanimated": "~3.17.4", |
||||||
|
"react-native-safe-area-context": "5.4.0", |
||||||
|
"react-native-screens": "~4.11.1", |
||||||
|
"react-native-web": "~0.20.0" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@babel/core": "^7.25.2", |
||||||
|
"@types/react": "~19.0.10", |
||||||
|
"jest": "^29.2.1", |
||||||
|
"jest-expo": "~53.0.8", |
||||||
|
"react-test-renderer": "19.0.0", |
||||||
|
"typescript": "~5.8.3" |
||||||
|
}, |
||||||
|
"private": true |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
{ |
||||||
|
"extends": "expo/tsconfig.base", |
||||||
|
"compilerOptions": { |
||||||
|
"strict": true, |
||||||
|
"paths": { |
||||||
|
"@/*": [ |
||||||
|
"./*" |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"**/*.ts", |
||||||
|
"**/*.tsx", |
||||||
|
".expo/types/**/*.ts", |
||||||
|
"expo-env.d.ts" |
||||||
|
] |
||||||
|
} |
Loading…
Reference in new issue