init commit

This commit is contained in:
Gabriel Brown 2024-09-09 22:57:42 -05:00
parent 741e8e4e2b
commit f65633c069
10 changed files with 190 additions and 164 deletions

6
.gitignore vendored
View File

@ -12,3 +12,9 @@ web-build/
# macOS # macOS
.DS_Store .DS_Store
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
# The following patterns were generated by expo-cli
expo-env.d.ts
# @end expo-cli

View File

@ -17,18 +17,27 @@ export default function TabLayout() {
<Tabs.Screen <Tabs.Screen
name="index" name="index"
options={{ options={{
title: 'Home', title: 'My Message',
tabBarIcon: ({ color, focused }) => ( tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'home' : 'home-outline'} color={color} /> <TabBarIcon name={focused ? 'mail' : 'mail-outline'} color={color} />
), ),
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="explore" name="sendmessage"
options={{ options={{
title: 'Explore', title: 'Send Message',
tabBarIcon: ({ color, focused }) => ( tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'code-slash' : 'code-slash-outline'} color={color} /> <TabBarIcon name={focused ? 'pencil' : 'pencil-outline'} color={color} />
),
}}
/>
<Tabs.Screen
name="countdown"
options={{
title: 'Countdown',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'time' : 'time-outline'} color={color} />
), ),
}} }}
/> />

92
app/(tabs)/countdown.tsx Normal file
View File

@ -0,0 +1,92 @@
import React, { useState, useEffect } from 'react';
import { StyleSheet } from 'react-native';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
export default function TabTwoScreen() {
const [countdown, setCountdown] = useState({
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});
const targetDate = new Date('2024-09-20T10:10:00').getTime();
useEffect(() => {
const interval = setInterval(() => {
const now = new Date().getTime();
const distance = targetDate - now;
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
setCountdown({ days, hours, minutes, seconds });
if (distance < 0) {
clearInterval(interval);
setCountdown({ days: 0, hours: 0, minutes: 0, seconds: 0 });
}
}, 1000);
return () => clearInterval(interval);
}, [targetDate]);
return (
<ThemedView style={styles.container}>
<ThemedText style={styles.title}>Countdown to Next Visit</ThemedText>
<ThemedView style={styles.countdownContainer}>
<CountdownItem value={countdown.days} label="Days" />
<CountdownItem value={countdown.hours} label="Hours" />
<CountdownItem value={countdown.minutes} label="Minutes" />
<CountdownItem value={countdown.seconds} label="Seconds" />
</ThemedView>
</ThemedView>
);
}
function CountdownItem({ value, label }) {
return (
<ThemedView style={styles.countdownItem}>
<ThemedText style={styles.countdownValue}>{value}</ThemedText>
<ThemedText style={styles.countdownLabel}>{label}</ThemedText>
</ThemedView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 56,
lineHeight: 64,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
paddingHorizontal: 20,
},
countdownContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
countdownItem: {
margin: 10,
lineHeight: 32,
alignItems: 'center',
},
countdownValue: {
fontSize: 32,
lineHeight: 32,
fontWeight: 'bold',
},
countdownLabel: {
fontSize: 24,
},
});

View File

@ -1,102 +0,0 @@
import Ionicons from '@expo/vector-icons/Ionicons';
import { StyleSheet, Image, Platform } from 'react-native';
import { Collapsible } from '@/components/Collapsible';
import { ExternalLink } from '@/components/ExternalLink';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
export default function TabTwoScreen() {
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
headerImage={<Ionicons size={310} name="code-slash" style={styles.headerImage} />}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Explore</ThemedText>
</ThemedView>
<ThemedText>This app includes example code to help you get started.</ThemedText>
<Collapsible title="File-based routing">
<ThemedText>
This app has two screens:{' '}
<ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '}
<ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText>
</ThemedText>
<ThemedText>
The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '}
sets up the tab navigator.
</ThemedText>
<ExternalLink href="https://docs.expo.dev/router/introduction">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Android, iOS, and web support">
<ThemedText>
You can open this project on Android, iOS, and the web. To open the web version, press{' '}
<ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project.
</ThemedText>
</Collapsible>
<Collapsible title="Images">
<ThemedText>
For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '}
<ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
different screen densities
</ThemedText>
<Image source={require('@/assets/images/react-logo.png')} style={{ alignSelf: 'center' }} />
<ExternalLink href="https://reactnative.dev/docs/images">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Custom fonts">
<ThemedText>
Open <ThemedText type="defaultSemiBold">app/_layout.tsx</ThemedText> to see how to load{' '}
<ThemedText style={{ fontFamily: 'SpaceMono' }}>
custom fonts such as this one.
</ThemedText>
</ThemedText>
<ExternalLink href="https://docs.expo.dev/versions/latest/sdk/font">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Light and dark mode components">
<ThemedText>
This template has light and dark mode support. The{' '}
<ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect
what the user's current color scheme is, and so you can adjust UI colors accordingly.
</ThemedText>
<ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Animations">
<ThemedText>
This template includes an example of an animated component. The{' '}
<ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText> library
to create a waving hand animation.
</ThemedText>
{Platform.select({
ios: (
<ThemedText>
The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '}
component provides a parallax effect for the header image.
</ThemedText>
),
})}
</Collapsible>
</ParallaxScrollView>
);
}
const styles = StyleSheet.create({
headerImage: {
color: '#808080',
bottom: -90,
left: -35,
position: 'absolute',
},
titleContainer: {
flexDirection: 'row',
gap: 8,
},
});

View File

@ -1,70 +1,29 @@
import { Image, StyleSheet, Platform } from 'react-native'; import { Image, StyleSheet, Platform } from 'react-native';
import { HelloWave } from '@/components/HelloWave';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText'; import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView'; import { ThemedView } from '@/components/ThemedView';
export default function HomeScreen() { export default function HomeScreen() {
const message = "This is the message";
return ( return (
<ParallaxScrollView <ThemedView style={styles.container}>
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }} <ThemedText style={styles.title}>{message}</ThemedText>
headerImage={
<Image
source={require('@/assets/images/partial-react-logo.png')}
style={styles.reactLogo}
/>
}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Welcome!</ThemedText>
<HelloWave />
</ThemedView> </ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 1: Try it</ThemedText>
<ThemedText>
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
Press{' '}
<ThemedText type="defaultSemiBold">
{Platform.select({ ios: 'cmd + d', android: 'cmd + m' })}
</ThemedText>{' '}
to open developer tools.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 2: Explore</ThemedText>
<ThemedText>
Tap the Explore tab to learn more about what's included in this starter app.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
<ThemedText>
When you're ready, run{' '}
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
</ThemedText>
</ThemedView>
</ParallaxScrollView>
); );
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
titleContainer: { container: {
flexDirection: 'row', flex: 1,
alignItems: 'center', alignItems: 'center',
gap: 8, justifyContent: 'center',
}, },
stepContainer: { title: {
gap: 8, fontSize: 56,
marginBottom: 8, lineHeight: 64,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
paddingHorizontal: 20,
}, },
reactLogo: { });
height: 178,
width: 290,
bottom: 0,
left: 0,
position: 'absolute',
},
});

View File

@ -0,0 +1,27 @@
import { Image, StyleSheet, Platform } from 'react-native';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
export default function HomeScreen() {
return (
<ThemedView style={styles.container}>
</ThemedView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 56,
lineHeight: 64,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
paddingHorizontal: 20,
},
});

0
assets/fonts/SpaceMono-Regular.ttf Executable file → Normal file
View File

34
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@expo/vector-icons": "^14.0.2", "@expo/vector-icons": "^14.0.2",
"@react-native-async-storage/async-storage": "^2.0.0",
"@react-navigation/native": "^6.0.2", "@react-navigation/native": "^6.0.2",
"expo": "~51.0.28", "expo": "~51.0.28",
"expo-constants": "~16.0.2", "expo-constants": "~16.0.2",
@ -4599,6 +4600,18 @@
"react": "^16.8 || ^17.0 || ^18.0" "react": "^16.8 || ^17.0 || ^18.0"
} }
}, },
"node_modules/@react-native-async-storage/async-storage": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.0.0.tgz",
"integrity": "sha512-af6H9JjfL6G/PktBfUivvexoiFKQTJGQCtSWxMdivLzNIY94mu9DdiY0JqCSg/LyPCLGKhHPUlRQhNvpu3/KVA==",
"license": "MIT",
"dependencies": {
"merge-options": "^3.0.4"
},
"peerDependencies": {
"react-native": "^0.0.0-0 || >=0.65 <1.0"
}
},
"node_modules/@react-native-community/cli": { "node_modules/@react-native-community/cli": {
"version": "13.6.9", "version": "13.6.9",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-13.6.9.tgz", "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-13.6.9.tgz",
@ -11684,6 +11697,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-plain-object": { "node_modules/is-plain-object": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@ -14935,6 +14957,18 @@
"integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==", "integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==",
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/merge-options": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
"license": "MIT",
"dependencies": {
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",

View File

@ -16,6 +16,7 @@
}, },
"dependencies": { "dependencies": {
"@expo/vector-icons": "^14.0.2", "@expo/vector-icons": "^14.0.2",
"@react-native-async-storage/async-storage": "^2.0.0",
"@react-navigation/native": "^6.0.2", "@react-navigation/native": "^6.0.2",
"expo": "~51.0.28", "expo": "~51.0.28",
"expo-constants": "~16.0.2", "expo-constants": "~16.0.2",

0
scripts/reset-project.js Executable file → Normal file
View File