diff --git a/.gitignore b/.gitignore index 05f2cff..04799d2 100644 --- a/.gitignore +++ b/.gitignore @@ -762,4 +762,9 @@ FodyWeavers.xsd -idea/ \ No newline at end of file +idea/ +# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb +# The following patterns were generated by expo-cli + +expo-env.d.ts +# @end expo-cli \ No newline at end of file diff --git a/TO REMOVE LATER/app/(tabs)/_layout.tsx b/TO REMOVE LATER/app/(tabs)/_layout.tsx deleted file mode 100644 index cfbc1e2..0000000 --- a/TO REMOVE LATER/app/(tabs)/_layout.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Tabs } from 'expo-router'; -import React from 'react'; -import { Platform } from 'react-native'; - -import { HapticTab } from '@/components/HapticTab'; -import { IconSymbol } from '@/components/ui/IconSymbol'; -import TabBarBackground from '@/components/ui/TabBarBackground'; -import { Colors } from '@/constants/Colors'; -import { useColorScheme } from '@/hooks/useColorScheme'; - -export default function TabLayout() { - const colorScheme = useColorScheme(); - - return ( - - , - }} - /> - , - }} - /> - - ); -} diff --git a/TO REMOVE LATER/app/(tabs)/explore.tsx b/TO REMOVE LATER/app/(tabs)/explore.tsx deleted file mode 100644 index 06e70c4..0000000 --- a/TO REMOVE LATER/app/(tabs)/explore.tsx +++ /dev/null @@ -1,109 +0,0 @@ -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'; -import { IconSymbol } from '@/components/ui/IconSymbol'; - -export default function TabTwoScreen() { - return ( - - }> - - Explore - - This app includes example code to help you get started. - - - This app has two screens:{' '} - app/(tabs)/index.tsx and{' '} - app/(tabs)/explore.tsx - - - The layout file in app/(tabs)/_layout.tsx{' '} - sets up the tab navigator. - - - Learn more - - - - - You can open this project on Android, iOS, and the web. To open the web version, press{' '} - w in the terminal running this project. - - - - - For static images, you can use the @2x and{' '} - @3x suffixes to provide files for - different screen densities - - - - Learn more - - - - - Open app/_layout.tsx to see how to load{' '} - - custom fonts such as this one. - - - - Learn more - - - - - This template has light and dark mode support. The{' '} - useColorScheme() hook lets you inspect - what the user's current color scheme is, and so you can adjust UI colors accordingly. - - - Learn more - - - - - This template includes an example of an animated component. The{' '} - components/HelloWave.tsx component uses - the powerful react-native-reanimated{' '} - library to create a waving hand animation. - - {Platform.select({ - ios: ( - - The components/ParallaxScrollView.tsx{' '} - component provides a parallax effect for the header image. - - ), - })} - - - ); -} - -const styles = StyleSheet.create({ - headerImage: { - color: '#808080', - bottom: -90, - left: -35, - position: 'absolute', - }, - titleContainer: { - flexDirection: 'row', - gap: 8, - }, -}); diff --git a/TO REMOVE LATER/app/(tabs)/index.tsx b/TO REMOVE LATER/app/(tabs)/index.tsx deleted file mode 100644 index 886b079..0000000 --- a/TO REMOVE LATER/app/(tabs)/index.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { Image, StyleSheet, Platform } from 'react-native'; - -import { HelloWave } from '@/components/HelloWave'; -import ParallaxScrollView from '@/components/ParallaxScrollView'; -import { ThemedText } from '@/components/ThemedText'; -import { ThemedView } from '@/components/ThemedView'; - -export default function HomeScreen() { - return ( - - }> - - Welcome! - - - - Step 1: Try it - - Edit app/(tabs)/index.tsx to see changes. - Press{' '} - - {Platform.select({ - ios: 'cmd + d', - android: 'cmd + m', - web: 'F12' - })} - {' '} - to open developer tools. - - - - Step 2: Explore - - Tap the Explore tab to learn more about what's included in this starter app. - - - - Step 3: Get a fresh start - - When you're ready, run{' '} - npm run reset-project to get a fresh{' '} - app directory. This will move the current{' '} - app to{' '} - app-example. - - - - ); -} - -const styles = StyleSheet.create({ - titleContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }, - stepContainer: { - gap: 8, - marginBottom: 8, - }, - reactLogo: { - height: 178, - width: 290, - bottom: 0, - left: 0, - position: 'absolute', - }, -}); diff --git a/TO REMOVE LATER/app/+not-found.tsx b/TO REMOVE LATER/app/+not-found.tsx deleted file mode 100644 index 963b04f..0000000 --- a/TO REMOVE LATER/app/+not-found.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Link, Stack } from 'expo-router'; -import { StyleSheet } from 'react-native'; - -import { ThemedText } from '@/components/ThemedText'; -import { ThemedView } from '@/components/ThemedView'; - -export default function NotFoundScreen() { - return ( - <> - - - This screen doesn't exist. - - Go to home screen! - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - padding: 20, - }, - link: { - marginTop: 15, - paddingVertical: 15, - }, -}); diff --git a/TO REMOVE LATER/app/_layout.tsx b/TO REMOVE LATER/app/_layout.tsx deleted file mode 100644 index db74578..0000000 --- a/TO REMOVE LATER/app/_layout.tsx +++ /dev/null @@ -1,39 +0,0 @@ -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 { StatusBar } from 'expo-status-bar'; -import { useEffect } from 'react'; -import 'react-native-reanimated'; - -import { useColorScheme } from '@/hooks/useColorScheme'; - -// Prevent the splash screen from auto-hiding before asset loading is complete. -SplashScreen.preventAutoHideAsync(); - -export default function RootLayout() { - const colorScheme = useColorScheme(); - const [loaded] = useFonts({ - SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), - }); - - useEffect(() => { - if (loaded) { - SplashScreen.hideAsync(); - } - }, [loaded]); - - if (!loaded) { - return null; - } - - return ( - - - - - - - - ); -} diff --git a/TO REMOVE LATER/components/Collapsible.tsx b/TO REMOVE LATER/components/Collapsible.tsx deleted file mode 100644 index 55bff2f..0000000 --- a/TO REMOVE LATER/components/Collapsible.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { PropsWithChildren, useState } from 'react'; -import { StyleSheet, TouchableOpacity } from 'react-native'; - -import { ThemedText } from '@/components/ThemedText'; -import { ThemedView } from '@/components/ThemedView'; -import { IconSymbol } from '@/components/ui/IconSymbol'; -import { Colors } from '@/constants/Colors'; -import { useColorScheme } from '@/hooks/useColorScheme'; - -export function Collapsible({ children, title }: PropsWithChildren & { title: string }) { - const [isOpen, setIsOpen] = useState(false); - const theme = useColorScheme() ?? 'light'; - - return ( - - setIsOpen((value) => !value)} - activeOpacity={0.8}> - - - {title} - - {isOpen && {children}} - - ); -} - -const styles = StyleSheet.create({ - heading: { - flexDirection: 'row', - alignItems: 'center', - gap: 6, - }, - content: { - marginTop: 6, - marginLeft: 24, - }, -}); diff --git a/TO REMOVE LATER/components/ExternalLink.tsx b/TO REMOVE LATER/components/ExternalLink.tsx deleted file mode 100644 index 8f05675..0000000 --- a/TO REMOVE LATER/components/ExternalLink.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Link } from 'expo-router'; -import { openBrowserAsync } from 'expo-web-browser'; -import { type ComponentProps } from 'react'; -import { Platform } from 'react-native'; - -type Props = Omit, 'href'> & { href: string }; - -export function ExternalLink({ href, ...rest }: Props) { - return ( - { - if (Platform.OS !== 'web') { - // Prevent the default behavior of linking to the default browser on native. - event.preventDefault(); - // Open the link in an in-app browser. - await openBrowserAsync(href); - } - }} - /> - ); -} diff --git a/TO REMOVE LATER/components/HapticTab.tsx b/TO REMOVE LATER/components/HapticTab.tsx deleted file mode 100644 index 7f3981c..0000000 --- a/TO REMOVE LATER/components/HapticTab.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs'; -import { PlatformPressable } from '@react-navigation/elements'; -import * as Haptics from 'expo-haptics'; - -export function HapticTab(props: BottomTabBarButtonProps) { - return ( - { - if (process.env.EXPO_OS === 'ios') { - // Add a soft haptic feedback when pressing down on the tabs. - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); - } - props.onPressIn?.(ev); - }} - /> - ); -} diff --git a/TO REMOVE LATER/components/HelloWave.tsx b/TO REMOVE LATER/components/HelloWave.tsx deleted file mode 100644 index 9b4bc31..0000000 --- a/TO REMOVE LATER/components/HelloWave.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { useEffect } from 'react'; -import { StyleSheet } from 'react-native'; -import Animated, { - useSharedValue, - useAnimatedStyle, - withTiming, - withRepeat, - withSequence, -} from 'react-native-reanimated'; - -import { ThemedText } from '@/components/ThemedText'; - -export function HelloWave() { - const rotationAnimation = useSharedValue(0); - - useEffect(() => { - rotationAnimation.value = withRepeat( - withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })), - 4 // Run the animation 4 times - ); - }, []); - - const animatedStyle = useAnimatedStyle(() => ({ - transform: [{ rotate: `${rotationAnimation.value}deg` }], - })); - - return ( - - 👋 - - ); -} - -const styles = StyleSheet.create({ - text: { - fontSize: 28, - lineHeight: 32, - marginTop: -6, - }, -}); diff --git a/TO REMOVE LATER/components/ParallaxScrollView.tsx b/TO REMOVE LATER/components/ParallaxScrollView.tsx deleted file mode 100644 index 5df1d75..0000000 --- a/TO REMOVE LATER/components/ParallaxScrollView.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import type { PropsWithChildren, ReactElement } from 'react'; -import { StyleSheet } from 'react-native'; -import Animated, { - interpolate, - useAnimatedRef, - useAnimatedStyle, - useScrollViewOffset, -} from 'react-native-reanimated'; - -import { ThemedView } from '@/components/ThemedView'; -import { useBottomTabOverflow } from '@/components/ui/TabBarBackground'; -import { useColorScheme } from '@/hooks/useColorScheme'; - -const HEADER_HEIGHT = 250; - -type Props = PropsWithChildren<{ - headerImage: ReactElement; - headerBackgroundColor: { dark: string; light: string }; -}>; - -export default function ParallaxScrollView({ - children, - headerImage, - headerBackgroundColor, -}: Props) { - const colorScheme = useColorScheme() ?? 'light'; - const scrollRef = useAnimatedRef(); - const scrollOffset = useScrollViewOffset(scrollRef); - const bottom = useBottomTabOverflow(); - const headerAnimatedStyle = useAnimatedStyle(() => { - return { - transform: [ - { - translateY: interpolate( - scrollOffset.value, - [-HEADER_HEIGHT, 0, HEADER_HEIGHT], - [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75] - ), - }, - { - scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]), - }, - ], - }; - }); - - return ( - - - - {headerImage} - - {children} - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - header: { - height: HEADER_HEIGHT, - overflow: 'hidden', - }, - content: { - flex: 1, - padding: 32, - gap: 16, - overflow: 'hidden', - }, -}); diff --git a/TO REMOVE LATER/components/ThemedText.tsx b/TO REMOVE LATER/components/ThemedText.tsx deleted file mode 100644 index c0e1a78..0000000 --- a/TO REMOVE LATER/components/ThemedText.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Text, type TextProps, StyleSheet } from 'react-native'; - -import { useThemeColor } from '@/hooks/useThemeColor'; - -export type ThemedTextProps = TextProps & { - lightColor?: string; - darkColor?: string; - type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; -}; - -export function ThemedText({ - style, - lightColor, - darkColor, - type = 'default', - ...rest -}: ThemedTextProps) { - const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); - - return ( - - ); -} - -const styles = StyleSheet.create({ - default: { - fontSize: 16, - lineHeight: 24, - }, - defaultSemiBold: { - fontSize: 16, - lineHeight: 24, - fontWeight: '600', - }, - title: { - fontSize: 32, - fontWeight: 'bold', - lineHeight: 32, - }, - subtitle: { - fontSize: 20, - fontWeight: 'bold', - }, - link: { - lineHeight: 30, - fontSize: 16, - color: '#0a7ea4', - }, -}); diff --git a/TO REMOVE LATER/components/ThemedView.tsx b/TO REMOVE LATER/components/ThemedView.tsx deleted file mode 100644 index 4d2cb09..0000000 --- a/TO REMOVE LATER/components/ThemedView.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { View, type ViewProps } from 'react-native'; - -import { useThemeColor } from '@/hooks/useThemeColor'; - -export type ThemedViewProps = ViewProps & { - lightColor?: string; - darkColor?: string; -}; - -export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) { - const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background'); - - return ; -} diff --git a/TO REMOVE LATER/components/__tests__/ThemedText-test.tsx b/TO REMOVE LATER/components/__tests__/ThemedText-test.tsx deleted file mode 100644 index 1ac3225..0000000 --- a/TO REMOVE LATER/components/__tests__/ThemedText-test.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import * as React from 'react'; -import renderer from 'react-test-renderer'; - -import { ThemedText } from '../ThemedText'; - -it(`renders correctly`, () => { - const tree = renderer.create(Snapshot test!).toJSON(); - - expect(tree).toMatchSnapshot(); -}); diff --git a/TO REMOVE LATER/components/__tests__/__snapshots__/ThemedText-test.tsx.snap b/TO REMOVE LATER/components/__tests__/__snapshots__/ThemedText-test.tsx.snap deleted file mode 100644 index b68e53e..0000000 --- a/TO REMOVE LATER/components/__tests__/__snapshots__/ThemedText-test.tsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` - - Snapshot test! - -`; diff --git a/TO REMOVE LATER/components/ui/IconSymbol.ios.tsx b/TO REMOVE LATER/components/ui/IconSymbol.ios.tsx deleted file mode 100644 index 9177f4d..0000000 --- a/TO REMOVE LATER/components/ui/IconSymbol.ios.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols'; -import { StyleProp, ViewStyle } from 'react-native'; - -export function IconSymbol({ - name, - size = 24, - color, - style, - weight = 'regular', -}: { - name: SymbolViewProps['name']; - size?: number; - color: string; - style?: StyleProp; - weight?: SymbolWeight; -}) { - return ( - - ); -} diff --git a/TO REMOVE LATER/components/ui/IconSymbol.tsx b/TO REMOVE LATER/components/ui/IconSymbol.tsx deleted file mode 100644 index f1fabd4..0000000 --- a/TO REMOVE LATER/components/ui/IconSymbol.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// This file is a fallback for using MaterialIcons on Android and web. - -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { SymbolWeight } from 'expo-symbols'; -import React from 'react'; -import { OpaqueColorValue, StyleProp, ViewStyle } from 'react-native'; - -// Add your SFSymbol to MaterialIcons mappings here. -const MAPPING = { - // See MaterialIcons here: https://icons.expo.fyi - // See SF Symbols in the SF Symbols app on Mac. - 'house.fill': 'home', - 'paperplane.fill': 'send', - 'chevron.left.forwardslash.chevron.right': 'code', - 'chevron.right': 'chevron-right', -} as Partial< - Record< - import('expo-symbols').SymbolViewProps['name'], - React.ComponentProps['name'] - > ->; - -export type IconSymbolName = keyof typeof MAPPING; - -/** - * An icon component that uses native SFSymbols on iOS, and MaterialIcons on Android and web. This ensures a consistent look across platforms, and optimal resource usage. - * - * Icon `name`s are based on SFSymbols and require manual mapping to MaterialIcons. - */ -export function IconSymbol({ - name, - size = 24, - color, - style, -}: { - name: IconSymbolName; - size?: number; - color: string | OpaqueColorValue; - style?: StyleProp; - weight?: SymbolWeight; -}) { - return ; -} diff --git a/TO REMOVE LATER/components/ui/TabBarBackground.ios.tsx b/TO REMOVE LATER/components/ui/TabBarBackground.ios.tsx deleted file mode 100644 index 6668e78..0000000 --- a/TO REMOVE LATER/components/ui/TabBarBackground.ios.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs'; -import { BlurView } from 'expo-blur'; -import { StyleSheet } from 'react-native'; -import { useSafeAreaInsets } from 'react-native-safe-area-context'; - -export default function BlurTabBarBackground() { - return ( - - ); -} - -export function useBottomTabOverflow() { - const tabHeight = useBottomTabBarHeight(); - const { bottom } = useSafeAreaInsets(); - return tabHeight - bottom; -} diff --git a/TO REMOVE LATER/components/ui/TabBarBackground.tsx b/TO REMOVE LATER/components/ui/TabBarBackground.tsx deleted file mode 100644 index 70d1c3c..0000000 --- a/TO REMOVE LATER/components/ui/TabBarBackground.tsx +++ /dev/null @@ -1,6 +0,0 @@ -// This is a shim for web and Android where the tab bar is generally opaque. -export default undefined; - -export function useBottomTabOverflow() { - return 0; -} diff --git a/TO REMOVE LATER/constants/Colors.ts b/TO REMOVE LATER/constants/Colors.ts deleted file mode 100644 index 14e6784..0000000 --- a/TO REMOVE LATER/constants/Colors.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Below are the colors that are used in the app. The colors are defined in the light and dark mode. - * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc. - */ - -const tintColorLight = '#0a7ea4'; -const tintColorDark = '#fff'; - -export const Colors = { - light: { - text: '#11181C', - background: '#fff', - tint: tintColorLight, - icon: '#687076', - tabIconDefault: '#687076', - tabIconSelected: tintColorLight, - }, - dark: { - text: '#ECEDEE', - background: '#151718', - tint: tintColorDark, - icon: '#9BA1A6', - tabIconDefault: '#9BA1A6', - tabIconSelected: tintColorDark, - }, -}; diff --git a/TO REMOVE LATER/hooks/useColorScheme.ts b/TO REMOVE LATER/hooks/useColorScheme.ts deleted file mode 100644 index 17e3c63..0000000 --- a/TO REMOVE LATER/hooks/useColorScheme.ts +++ /dev/null @@ -1 +0,0 @@ -export { useColorScheme } from 'react-native'; diff --git a/TO REMOVE LATER/hooks/useColorScheme.web.ts b/TO REMOVE LATER/hooks/useColorScheme.web.ts deleted file mode 100644 index 7eb1c1b..0000000 --- a/TO REMOVE LATER/hooks/useColorScheme.web.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useState } from 'react'; -import { useColorScheme as useRNColorScheme } from 'react-native'; - -/** - * To support static rendering, this value needs to be re-calculated on the client side for web - */ -export function useColorScheme() { - const [hasHydrated, setHasHydrated] = useState(false); - - useEffect(() => { - setHasHydrated(true); - }, []); - - const colorScheme = useRNColorScheme(); - - if (hasHydrated) { - return colorScheme; - } - - return 'light'; -} diff --git a/TO REMOVE LATER/hooks/useThemeColor.ts b/TO REMOVE LATER/hooks/useThemeColor.ts deleted file mode 100644 index 0608e73..0000000 --- a/TO REMOVE LATER/hooks/useThemeColor.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Learn more about light and dark modes: - * https://docs.expo.dev/guides/color-schemes/ - */ - -import { Colors } from '@/constants/Colors'; -import { useColorScheme } from '@/hooks/useColorScheme'; - -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]; - } -} diff --git a/TO REMOVE LATER/scripts/reset-project.js b/TO REMOVE LATER/scripts/reset-project.js deleted file mode 100644 index 5f81463..0000000 --- a/TO REMOVE LATER/scripts/reset-project.js +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env node - -/** - * This script is used to reset the project to a blank state. - * It moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file. - * You can remove the `reset-project` script from package.json and safely delete this file after running it. - */ - -const fs = require("fs"); -const path = require("path"); - -const root = process.cwd(); -const oldDirs = ["app", "components", "hooks", "constants", "scripts"]; -const newDir = "app-example"; -const newAppDir = "app"; -const newDirPath = path.join(root, newDir); - -const indexContent = `import { Text, View } from "react-native"; - -export default function Index() { - return ( - - Edit app/index.tsx to edit this screen. - - ); -} -`; - -const layoutContent = `import { Stack } from "expo-router"; - -export default function RootLayout() { - return ; -} -`; - -const moveDirectories = async () => { - try { - // Create the app-example directory - await fs.promises.mkdir(newDirPath, { recursive: true }); - console.log(`📁 /${newDir} directory created.`); - - // Move old directories to new app-example directory - for (const dir of oldDirs) { - const oldDirPath = path.join(root, dir); - const newDirPath = path.join(root, newDir, dir); - if (fs.existsSync(oldDirPath)) { - await fs.promises.rename(oldDirPath, newDirPath); - console.log(`➡️ /${dir} moved to /${newDir}/${dir}.`); - } else { - console.log(`➡️ /${dir} does not exist, skipping.`); - } - } - - // Create new /app directory - const newAppDirPath = path.join(root, newAppDir); - await fs.promises.mkdir(newAppDirPath, { recursive: true }); - console.log("\n📁 New /app directory created."); - - // Create index.tsx - const indexPath = path.join(newAppDirPath, "index.tsx"); - await fs.promises.writeFile(indexPath, indexContent); - console.log("📄 app/index.tsx created."); - - // Create _layout.tsx - const layoutPath = path.join(newAppDirPath, "_layout.tsx"); - await fs.promises.writeFile(layoutPath, layoutContent); - console.log("📄 app/_layout.tsx created."); - - console.log("\n✅ Project reset complete. Next steps:"); - console.log( - "1. Run `npx expo start` to start a development server.\n2. Edit app/index.tsx to edit the main screen.\n3. Delete the /app-example directory when you're done referencing it." - ); - } catch (error) { - console.error(`Error during script execution: ${error}`); - } -}; - -moveDirectories(); diff --git a/app/_layout.tsx b/app/_layout.tsx index d6a88a7..da0ddcb 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,12 +1,53 @@ -import { Stack } from "expo-router"; +import {Stack, Tabs} from "expo-router"; import "../global.css"; import { GluestackUIProvider } from "./src/components/ui/gluestack-ui-provider"; - +import HomeScreen from "@/src/screen/HomeScreen"; +import ProfileScreen from "@/src/screen/ProfileScreen"; +import React from "react"; +import Navigation from "@/src/navigation/navigation"; +import {SafeAreaView} from "react-native"; +import {createBottomTabNavigator} from "@react-navigation/bottom-tabs"; +import {AntDesign, MaterialIcons} from "@expo/vector-icons"; export default function RootLayout() { - return ( - - - - ); + const BottomTabNavigator = createBottomTabNavigator(); + return ( + + + + + ( + + ), + }} + /> + ( + + ), + }}/> + + + + + ); } + + + + + + + diff --git a/app/index.tsx b/app/index.tsx index 8a8ff67..7501f9c 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -1,9 +1,21 @@ -import { Text, View } from "react-native"; +import {SafeAreaView, Text, View} from "react-native"; +import Navigation from "@/src/navigation/navigation"; +import HomeScreen from "@/src/screen/HomeScreen"; export default function Index() { return ( - Edit app/index.tsx to edit this screen. + ); } + + +function App() { + return ( + + + + + ); +} \ No newline at end of file diff --git a/app/src/components/ui/text/index.tsx b/app/src/components/ui/text/index.tsx new file mode 100644 index 0000000..c662b72 --- /dev/null +++ b/app/src/components/ui/text/index.tsx @@ -0,0 +1,48 @@ +import React from 'react'; + +import type { VariantProps } from '@gluestack-ui/nativewind-utils'; +import { Text as RNText } from 'react-native'; +import { textStyle } from './styles'; + +type ITextProps = React.ComponentProps & + VariantProps; + +const Text = React.forwardRef, ITextProps>( + ( + { + className, + isTruncated, + bold, + underline, + strikeThrough, + size = 'md', + sub, + italic, + highlight, + ...props + }, + ref + ) => { + return ( + + ); + } +); + +Text.displayName = 'Text'; + +export { Text }; diff --git a/app/src/components/ui/text/index.web.tsx b/app/src/components/ui/text/index.web.tsx new file mode 100644 index 0000000..4abb61c --- /dev/null +++ b/app/src/components/ui/text/index.web.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/nativewind-utils'; +import { textStyle } from './styles'; + +type ITextProps = React.ComponentProps<'span'> & VariantProps; + +const Text = React.forwardRef, ITextProps>( + ( + { + className, + isTruncated, + bold, + underline, + strikeThrough, + size = 'md', + sub, + italic, + highlight, + ...props + }: { className?: string } & ITextProps, + ref + ) => { + return ( + + ); + } +); + +Text.displayName = 'Text'; + +export { Text }; diff --git a/app/src/components/ui/text/styles.tsx b/app/src/components/ui/text/styles.tsx new file mode 100644 index 0000000..7a6b8f6 --- /dev/null +++ b/app/src/components/ui/text/styles.tsx @@ -0,0 +1,47 @@ +import { tva } from '@gluestack-ui/nativewind-utils/tva'; +import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb'; + +const baseStyle = isWeb + ? 'font-sans tracking-sm my-0 bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word' + : ''; + +export const textStyle = tva({ + base: `text-typography-700 font-body ${baseStyle}`, + + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); diff --git a/package-lock.json b/package-lock.json index ca569a8..91d3c5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "@gluestack-ui/toast": "^1.0.8", "@react-navigation/bottom-tabs": "^7.2.0", "@react-navigation/native": "^7.0.14", + "@react-navigation/native-stack": "^7.2.0", + "@react-navigation/stack": "^7.1.1", "expo": "~52.0.24", "expo-blur": "~14.0.1", "expo-constants": "~17.0.3", @@ -34,9 +36,10 @@ "react-native": "0.76.5", "react-native-gesture-handler": "~2.20.2", "react-native-reanimated": "~3.16.1", - "react-native-safe-area-context": "^4.12.0", + "react-native-safe-area-context": "^4.14.1", "react-native-screens": "~4.4.0", "react-native-svg": "^15.11.0", + "react-native-vector-icons": "^10.2.0", "react-native-web": "~0.19.13", "react-native-webview": "13.12.5", "tailwindcss": "^3.4.17" @@ -3854,6 +3857,24 @@ "nanoid": "3.3.8" } }, + "node_modules/@react-navigation/stack": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-7.1.1.tgz", + "integrity": "sha512-CBTKQlIkELp05zRiTAv5Pa7OMuCpKyBXcdB3PGMN2Mm55/5MkDsA1IaZorp/6TsVCdllITD6aTbGX/HA/88A6w==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.2.5", + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-gesture-handler": ">= 2.0.0", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, "node_modules/@react-stately/overlays": { "version": "3.6.12", "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.12.tgz", @@ -12382,9 +12403,9 @@ } }, "node_modules/react-native-safe-area-context": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.12.0.tgz", - "integrity": "sha512-ukk5PxcF4p3yu6qMZcmeiZgowhb5AsKRnil54YFUUAXVIS7PJcMHGGC+q44fCiBg44/1AJk5njGMez1m9H0BVQ==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.14.1.tgz", + "integrity": "sha512-+tUhT5WBl8nh5+P+chYhAjR470iCByf9z5EYdCEbPaAK3Yfzw+o8VRPnUgmPAKlSccOgQBxx3NOl/Wzckn9ujg==", "license": "MIT", "peerDependencies": { "react": "*", @@ -12420,6 +12441,92 @@ "react-native": "*" } }, + "node_modules/react-native-vector-icons": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz", + "integrity": "sha512-n5HGcxUuVaTf9QJPs/W22xQpC2Z9u0nb0KgLPnVltP8vdUvOp6+R26gF55kilP/fV4eL4vsAHUqUjewppJMBOQ==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2", + "yargs": "^16.1.1" + }, + "bin": { + "fa-upgrade.sh": "bin/fa-upgrade.sh", + "fa5-upgrade": "bin/fa5-upgrade.sh", + "fa6-upgrade": "bin/fa6-upgrade.sh", + "generate-icon": "bin/generate-icon.js" + } + }, + "node_modules/react-native-vector-icons/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/react-native-vector-icons/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/react-native-vector-icons/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-vector-icons/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-vector-icons/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-vector-icons/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/react-native-web": { "version": "0.19.13", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.13.tgz", diff --git a/package.json b/package.json index 3b9a7c4..bb93596 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "@gluestack-ui/toast": "^1.0.8", "@react-navigation/bottom-tabs": "^7.2.0", "@react-navigation/native": "^7.0.14", + "@react-navigation/native-stack": "^7.2.0", + "@react-navigation/stack": "^7.1.1", "expo": "~52.0.24", "expo-blur": "~14.0.1", "expo-constants": "~17.0.3", @@ -41,9 +43,10 @@ "react-native": "0.76.5", "react-native-gesture-handler": "~2.20.2", "react-native-reanimated": "~3.16.1", - "react-native-safe-area-context": "^4.12.0", + "react-native-safe-area-context": "^4.14.1", "react-native-screens": "~4.4.0", "react-native-svg": "^15.11.0", + "react-native-vector-icons": "^10.2.0", "react-native-web": "~0.19.13", "react-native-webview": "13.12.5", "tailwindcss": "^3.4.17" diff --git a/src/navigation/component.ts b/src/navigation/component.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/navigation/navigation.tsx b/src/navigation/navigation.tsx new file mode 100644 index 0000000..af983d3 --- /dev/null +++ b/src/navigation/navigation.tsx @@ -0,0 +1,38 @@ +import {createBottomTabNavigator} from "@react-navigation/bottom-tabs"; +import {NavigationContainer} from "expo-router/build/fork/NavigationContainer"; +import ProfileScreen from "@/src/screen/ProfileScreen"; +import HomeScreen from "@/src/screen/HomeScreen"; +import {MaterialIcons} from "@expo/vector-icons"; + +export default function Navigation() { + /* const BottomTabNavigator = createBottomTabNavigator(); + + return ( + + + ( + + ), + }} + /> + + + + + ) + */ + +} \ No newline at end of file diff --git a/src/screen/HomeScreen.tsx b/src/screen/HomeScreen.tsx new file mode 100644 index 0000000..85856f3 --- /dev/null +++ b/src/screen/HomeScreen.tsx @@ -0,0 +1,13 @@ +import {View, Text, SafeAreaView} from "react-native"; + + +export default function HomeScreen() { + return ( + + + Edit src/screen/HomeScreen.tsx to edit this screen. + + + + ); +} \ No newline at end of file diff --git a/src/screen/ProfileScreen.tsx b/src/screen/ProfileScreen.tsx new file mode 100644 index 0000000..bdd0e0d --- /dev/null +++ b/src/screen/ProfileScreen.tsx @@ -0,0 +1,13 @@ +import {SafeAreaView, View} from "react-native"; +import {Text} from "react-native"; + +export default function ProfileScreen() { + return ( + + + Edit src/screen/ProfileScreen.tsx to edit this screen. + + + + ); +} \ No newline at end of file