frontend client for gemstone. decentralised workplace app
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: reset project

serenity c431f745 7466bdcb

+18 -836
-35
app/(tabs)/_layout.tsx
··· 1 - import { Tabs } from 'expo-router'; 2 - import React from 'react'; 3 - 4 - import { HapticTab } from '@/components/haptic-tab'; 5 - import { IconSymbol } from '@/components/ui/icon-symbol'; 6 - import { Colors } from '@/constants/theme'; 7 - import { useColorScheme } from '@/hooks/use-color-scheme'; 8 - 9 - export default function TabLayout() { 10 - const colorScheme = useColorScheme(); 11 - 12 - return ( 13 - <Tabs 14 - screenOptions={{ 15 - tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint, 16 - headerShown: false, 17 - tabBarButton: HapticTab, 18 - }}> 19 - <Tabs.Screen 20 - name="index" 21 - options={{ 22 - title: 'Home', 23 - tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />, 24 - }} 25 - /> 26 - <Tabs.Screen 27 - name="explore" 28 - options={{ 29 - title: 'Explore', 30 - tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />, 31 - }} 32 - /> 33 - </Tabs> 34 - ); 35 - }
-112
app/(tabs)/explore.tsx
··· 1 - import { Image } from 'expo-image'; 2 - import { Platform, StyleSheet } from 'react-native'; 3 - 4 - import { Collapsible } from '@/components/ui/collapsible'; 5 - import { ExternalLink } from '@/components/external-link'; 6 - import ParallaxScrollView from '@/components/parallax-scroll-view'; 7 - import { ThemedText } from '@/components/themed-text'; 8 - import { ThemedView } from '@/components/themed-view'; 9 - import { IconSymbol } from '@/components/ui/icon-symbol'; 10 - import { Fonts } from '@/constants/theme'; 11 - 12 - export default function TabTwoScreen() { 13 - return ( 14 - <ParallaxScrollView 15 - headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }} 16 - headerImage={ 17 - <IconSymbol 18 - size={310} 19 - color="#808080" 20 - name="chevron.left.forwardslash.chevron.right" 21 - style={styles.headerImage} 22 - /> 23 - }> 24 - <ThemedView style={styles.titleContainer}> 25 - <ThemedText 26 - type="title" 27 - style={{ 28 - fontFamily: Fonts.rounded, 29 - }}> 30 - Explore 31 - </ThemedText> 32 - </ThemedView> 33 - <ThemedText>This app includes example code to help you get started.</ThemedText> 34 - <Collapsible title="File-based routing"> 35 - <ThemedText> 36 - This app has two screens:{' '} 37 - <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '} 38 - <ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText> 39 - </ThemedText> 40 - <ThemedText> 41 - The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '} 42 - sets up the tab navigator. 43 - </ThemedText> 44 - <ExternalLink href="https://docs.expo.dev/router/introduction"> 45 - <ThemedText type="link">Learn more</ThemedText> 46 - </ExternalLink> 47 - </Collapsible> 48 - <Collapsible title="Android, iOS, and web support"> 49 - <ThemedText> 50 - You can open this project on Android, iOS, and the web. To open the web version, press{' '} 51 - <ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project. 52 - </ThemedText> 53 - </Collapsible> 54 - <Collapsible title="Images"> 55 - <ThemedText> 56 - For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '} 57 - <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for 58 - different screen densities 59 - </ThemedText> 60 - <Image 61 - source={require('@/assets/images/react-logo.png')} 62 - style={{ width: 100, height: 100, alignSelf: 'center' }} 63 - /> 64 - <ExternalLink href="https://reactnative.dev/docs/images"> 65 - <ThemedText type="link">Learn more</ThemedText> 66 - </ExternalLink> 67 - </Collapsible> 68 - <Collapsible title="Light and dark mode components"> 69 - <ThemedText> 70 - This template has light and dark mode support. The{' '} 71 - <ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect 72 - what the user&apos;s current color scheme is, and so you can adjust UI colors accordingly. 73 - </ThemedText> 74 - <ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/"> 75 - <ThemedText type="link">Learn more</ThemedText> 76 - </ExternalLink> 77 - </Collapsible> 78 - <Collapsible title="Animations"> 79 - <ThemedText> 80 - This template includes an example of an animated component. The{' '} 81 - <ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses 82 - the powerful{' '} 83 - <ThemedText type="defaultSemiBold" style={{ fontFamily: Fonts.mono }}> 84 - react-native-reanimated 85 - </ThemedText>{' '} 86 - library to create a waving hand animation. 87 - </ThemedText> 88 - {Platform.select({ 89 - ios: ( 90 - <ThemedText> 91 - The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '} 92 - component provides a parallax effect for the header image. 93 - </ThemedText> 94 - ), 95 - })} 96 - </Collapsible> 97 - </ParallaxScrollView> 98 - ); 99 - } 100 - 101 - const styles = StyleSheet.create({ 102 - headerImage: { 103 - color: '#808080', 104 - bottom: -90, 105 - left: -35, 106 - position: 'absolute', 107 - }, 108 - titleContainer: { 109 - flexDirection: 'row', 110 - gap: 8, 111 - }, 112 - });
-98
app/(tabs)/index.tsx
··· 1 - import { Image } from 'expo-image'; 2 - import { Platform, StyleSheet } from 'react-native'; 3 - 4 - import { HelloWave } from '@/components/hello-wave'; 5 - import ParallaxScrollView from '@/components/parallax-scroll-view'; 6 - import { ThemedText } from '@/components/themed-text'; 7 - import { ThemedView } from '@/components/themed-view'; 8 - import { Link } from 'expo-router'; 9 - 10 - export default function HomeScreen() { 11 - return ( 12 - <ParallaxScrollView 13 - headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }} 14 - headerImage={ 15 - <Image 16 - source={require('@/assets/images/partial-react-logo.png')} 17 - style={styles.reactLogo} 18 - /> 19 - }> 20 - <ThemedView style={styles.titleContainer}> 21 - <ThemedText type="title">Welcome!</ThemedText> 22 - <HelloWave /> 23 - </ThemedView> 24 - <ThemedView style={styles.stepContainer}> 25 - <ThemedText type="subtitle">Step 1: Try it</ThemedText> 26 - <ThemedText> 27 - Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes. 28 - Press{' '} 29 - <ThemedText type="defaultSemiBold"> 30 - {Platform.select({ 31 - ios: 'cmd + d', 32 - android: 'cmd + m', 33 - web: 'F12', 34 - })} 35 - </ThemedText>{' '} 36 - to open developer tools. 37 - </ThemedText> 38 - </ThemedView> 39 - <ThemedView style={styles.stepContainer}> 40 - <Link href="/modal"> 41 - <Link.Trigger> 42 - <ThemedText type="subtitle">Step 2: Explore</ThemedText> 43 - </Link.Trigger> 44 - <Link.Preview /> 45 - <Link.Menu> 46 - <Link.MenuAction title="Action" icon="cube" onPress={() => alert('Action pressed')} /> 47 - <Link.MenuAction 48 - title="Share" 49 - icon="square.and.arrow.up" 50 - onPress={() => alert('Share pressed')} 51 - /> 52 - <Link.Menu title="More" icon="ellipsis"> 53 - <Link.MenuAction 54 - title="Delete" 55 - icon="trash" 56 - destructive 57 - onPress={() => alert('Delete pressed')} 58 - /> 59 - </Link.Menu> 60 - </Link.Menu> 61 - </Link> 62 - 63 - <ThemedText> 64 - {`Tap the Explore tab to learn more about what's included in this starter app.`} 65 - </ThemedText> 66 - </ThemedView> 67 - <ThemedView style={styles.stepContainer}> 68 - <ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText> 69 - <ThemedText> 70 - {`When you're ready, run `} 71 - <ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '} 72 - <ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '} 73 - <ThemedText type="defaultSemiBold">app</ThemedText> to{' '} 74 - <ThemedText type="defaultSemiBold">app-example</ThemedText>. 75 - </ThemedText> 76 - </ThemedView> 77 - </ParallaxScrollView> 78 - ); 79 - } 80 - 81 - const styles = StyleSheet.create({ 82 - titleContainer: { 83 - flexDirection: 'row', 84 - alignItems: 'center', 85 - gap: 8, 86 - }, 87 - stepContainer: { 88 - gap: 8, 89 - marginBottom: 8, 90 - }, 91 - reactLogo: { 92 - height: 178, 93 - width: 290, 94 - bottom: 0, 95 - left: 0, 96 - position: 'absolute', 97 - }, 98 - });
+2 -21
app/_layout.tsx
··· 1 - import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; 2 - import { Stack } from 'expo-router'; 3 - import { StatusBar } from 'expo-status-bar'; 4 - import 'react-native-reanimated'; 5 - 6 - import { useColorScheme } from '@/hooks/use-color-scheme'; 7 - 8 - export const unstable_settings = { 9 - anchor: '(tabs)', 10 - }; 1 + import { Stack } from "expo-router"; 11 2 12 3 export default function RootLayout() { 13 - const colorScheme = useColorScheme(); 14 - 15 - return ( 16 - <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> 17 - <Stack> 18 - <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> 19 - <Stack.Screen name="modal" options={{ presentation: 'modal', title: 'Modal' }} /> 20 - </Stack> 21 - <StatusBar style="auto" /> 22 - </ThemeProvider> 23 - ); 4 + return <Stack />; 24 5 }
+16
app/index.tsx
··· 1 + import ChatComponent from "@/app/components/ChatComponent"; 2 + import { Text, View } from "react-native"; 3 + 4 + export default function Index() { 5 + return ( 6 + <View 7 + style={{ 8 + flex: 1, 9 + justifyContent: "center", 10 + alignItems: "center", 11 + }} 12 + > 13 + <Text>Edit app/index.tsx to edit this screen.</Text> 14 + </View> 15 + ); 16 + }
-29
app/modal.tsx
··· 1 - import { Link } from 'expo-router'; 2 - import { StyleSheet } from 'react-native'; 3 - 4 - import { ThemedText } from '@/components/themed-text'; 5 - import { ThemedView } from '@/components/themed-view'; 6 - 7 - export default function ModalScreen() { 8 - return ( 9 - <ThemedView style={styles.container}> 10 - <ThemedText type="title">This is a modal</ThemedText> 11 - <Link href="/" dismissTo style={styles.link}> 12 - <ThemedText type="link">Go to home screen</ThemedText> 13 - </Link> 14 - </ThemedView> 15 - ); 16 - } 17 - 18 - const styles = StyleSheet.create({ 19 - container: { 20 - flex: 1, 21 - alignItems: 'center', 22 - justifyContent: 'center', 23 - padding: 20, 24 - }, 25 - link: { 26 - marginTop: 15, 27 - paddingVertical: 15, 28 - }, 29 - });
-25
components/external-link.tsx
··· 1 - import { Href, Link } from 'expo-router'; 2 - import { openBrowserAsync, WebBrowserPresentationStyle } from 'expo-web-browser'; 3 - import { type ComponentProps } from 'react'; 4 - 5 - type Props = Omit<ComponentProps<typeof Link>, 'href'> & { href: Href & string }; 6 - 7 - export function ExternalLink({ href, ...rest }: Props) { 8 - return ( 9 - <Link 10 - target="_blank" 11 - {...rest} 12 - href={href} 13 - onPress={async (event) => { 14 - if (process.env.EXPO_OS !== 'web') { 15 - // Prevent the default behavior of linking to the default browser on native. 16 - event.preventDefault(); 17 - // Open the link in an in-app browser. 18 - await openBrowserAsync(href, { 19 - presentationStyle: WebBrowserPresentationStyle.AUTOMATIC, 20 - }); 21 - } 22 - }} 23 - /> 24 - ); 25 - }
-18
components/haptic-tab.tsx
··· 1 - import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs'; 2 - import { PlatformPressable } from '@react-navigation/elements'; 3 - import * as Haptics from 'expo-haptics'; 4 - 5 - export function HapticTab(props: BottomTabBarButtonProps) { 6 - return ( 7 - <PlatformPressable 8 - {...props} 9 - onPressIn={(ev) => { 10 - if (process.env.EXPO_OS === 'ios') { 11 - // Add a soft haptic feedback when pressing down on the tabs. 12 - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); 13 - } 14 - props.onPressIn?.(ev); 15 - }} 16 - /> 17 - ); 18 - }
-19
components/hello-wave.tsx
··· 1 - import Animated from 'react-native-reanimated'; 2 - 3 - export function HelloWave() { 4 - return ( 5 - <Animated.Text 6 - style={{ 7 - fontSize: 28, 8 - lineHeight: 32, 9 - marginTop: -6, 10 - animationName: { 11 - '50%': { transform: [{ rotate: '25deg' }] }, 12 - }, 13 - animationIterationCount: 4, 14 - animationDuration: '300ms', 15 - }}> 16 - ๐Ÿ‘‹ 17 - </Animated.Text> 18 - ); 19 - }
-79
components/parallax-scroll-view.tsx
··· 1 - import type { PropsWithChildren, ReactElement } from 'react'; 2 - import { StyleSheet } from 'react-native'; 3 - import Animated, { 4 - interpolate, 5 - useAnimatedRef, 6 - useAnimatedStyle, 7 - useScrollOffset, 8 - } from 'react-native-reanimated'; 9 - 10 - import { ThemedView } from '@/components/themed-view'; 11 - import { useColorScheme } from '@/hooks/use-color-scheme'; 12 - import { useThemeColor } from '@/hooks/use-theme-color'; 13 - 14 - const HEADER_HEIGHT = 250; 15 - 16 - type Props = PropsWithChildren<{ 17 - headerImage: ReactElement; 18 - headerBackgroundColor: { dark: string; light: string }; 19 - }>; 20 - 21 - export default function ParallaxScrollView({ 22 - children, 23 - headerImage, 24 - headerBackgroundColor, 25 - }: Props) { 26 - const backgroundColor = useThemeColor({}, 'background'); 27 - const colorScheme = useColorScheme() ?? 'light'; 28 - const scrollRef = useAnimatedRef<Animated.ScrollView>(); 29 - const scrollOffset = useScrollOffset(scrollRef); 30 - const headerAnimatedStyle = useAnimatedStyle(() => { 31 - return { 32 - transform: [ 33 - { 34 - translateY: interpolate( 35 - scrollOffset.value, 36 - [-HEADER_HEIGHT, 0, HEADER_HEIGHT], 37 - [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75] 38 - ), 39 - }, 40 - { 41 - scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]), 42 - }, 43 - ], 44 - }; 45 - }); 46 - 47 - return ( 48 - <Animated.ScrollView 49 - ref={scrollRef} 50 - style={{ backgroundColor, flex: 1 }} 51 - scrollEventThrottle={16}> 52 - <Animated.View 53 - style={[ 54 - styles.header, 55 - { backgroundColor: headerBackgroundColor[colorScheme] }, 56 - headerAnimatedStyle, 57 - ]}> 58 - {headerImage} 59 - </Animated.View> 60 - <ThemedView style={styles.content}>{children}</ThemedView> 61 - </Animated.ScrollView> 62 - ); 63 - } 64 - 65 - const styles = StyleSheet.create({ 66 - container: { 67 - flex: 1, 68 - }, 69 - header: { 70 - height: HEADER_HEIGHT, 71 - overflow: 'hidden', 72 - }, 73 - content: { 74 - flex: 1, 75 - padding: 32, 76 - gap: 16, 77 - overflow: 'hidden', 78 - }, 79 - });
-60
components/themed-text.tsx
··· 1 - import { StyleSheet, Text, type TextProps } from 'react-native'; 2 - 3 - import { useThemeColor } from '@/hooks/use-theme-color'; 4 - 5 - export type ThemedTextProps = TextProps & { 6 - lightColor?: string; 7 - darkColor?: string; 8 - type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; 9 - }; 10 - 11 - export function ThemedText({ 12 - style, 13 - lightColor, 14 - darkColor, 15 - type = 'default', 16 - ...rest 17 - }: ThemedTextProps) { 18 - const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); 19 - 20 - return ( 21 - <Text 22 - style={[ 23 - { color }, 24 - type === 'default' ? styles.default : undefined, 25 - type === 'title' ? styles.title : undefined, 26 - type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined, 27 - type === 'subtitle' ? styles.subtitle : undefined, 28 - type === 'link' ? styles.link : undefined, 29 - style, 30 - ]} 31 - {...rest} 32 - /> 33 - ); 34 - } 35 - 36 - const styles = StyleSheet.create({ 37 - default: { 38 - fontSize: 16, 39 - lineHeight: 24, 40 - }, 41 - defaultSemiBold: { 42 - fontSize: 16, 43 - lineHeight: 24, 44 - fontWeight: '600', 45 - }, 46 - title: { 47 - fontSize: 32, 48 - fontWeight: 'bold', 49 - lineHeight: 32, 50 - }, 51 - subtitle: { 52 - fontSize: 20, 53 - fontWeight: 'bold', 54 - }, 55 - link: { 56 - lineHeight: 30, 57 - fontSize: 16, 58 - color: '#0a7ea4', 59 - }, 60 - });
-14
components/themed-view.tsx
··· 1 - import { View, type ViewProps } from 'react-native'; 2 - 3 - import { useThemeColor } from '@/hooks/use-theme-color'; 4 - 5 - export type ThemedViewProps = ViewProps & { 6 - lightColor?: string; 7 - darkColor?: string; 8 - }; 9 - 10 - export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) { 11 - const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background'); 12 - 13 - return <View style={[{ backgroundColor }, style]} {...otherProps} />; 14 - }
-45
components/ui/collapsible.tsx
··· 1 - import { PropsWithChildren, useState } from 'react'; 2 - import { StyleSheet, TouchableOpacity } from 'react-native'; 3 - 4 - import { ThemedText } from '@/components/themed-text'; 5 - import { ThemedView } from '@/components/themed-view'; 6 - import { IconSymbol } from '@/components/ui/icon-symbol'; 7 - import { Colors } from '@/constants/theme'; 8 - import { useColorScheme } from '@/hooks/use-color-scheme'; 9 - 10 - export function Collapsible({ children, title }: PropsWithChildren & { title: string }) { 11 - const [isOpen, setIsOpen] = useState(false); 12 - const theme = useColorScheme() ?? 'light'; 13 - 14 - return ( 15 - <ThemedView> 16 - <TouchableOpacity 17 - style={styles.heading} 18 - onPress={() => setIsOpen((value) => !value)} 19 - activeOpacity={0.8}> 20 - <IconSymbol 21 - name="chevron.right" 22 - size={18} 23 - weight="medium" 24 - color={theme === 'light' ? Colors.light.icon : Colors.dark.icon} 25 - style={{ transform: [{ rotate: isOpen ? '90deg' : '0deg' }] }} 26 - /> 27 - 28 - <ThemedText type="defaultSemiBold">{title}</ThemedText> 29 - </TouchableOpacity> 30 - {isOpen && <ThemedView style={styles.content}>{children}</ThemedView>} 31 - </ThemedView> 32 - ); 33 - } 34 - 35 - const styles = StyleSheet.create({ 36 - heading: { 37 - flexDirection: 'row', 38 - alignItems: 'center', 39 - gap: 6, 40 - }, 41 - content: { 42 - marginTop: 6, 43 - marginLeft: 24, 44 - }, 45 - });
-32
components/ui/icon-symbol.ios.tsx
··· 1 - import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols'; 2 - import { StyleProp, ViewStyle } from 'react-native'; 3 - 4 - export function IconSymbol({ 5 - name, 6 - size = 24, 7 - color, 8 - style, 9 - weight = 'regular', 10 - }: { 11 - name: SymbolViewProps['name']; 12 - size?: number; 13 - color: string; 14 - style?: StyleProp<ViewStyle>; 15 - weight?: SymbolWeight; 16 - }) { 17 - return ( 18 - <SymbolView 19 - weight={weight} 20 - tintColor={color} 21 - resizeMode="scaleAspectFit" 22 - name={name} 23 - style={[ 24 - { 25 - width: size, 26 - height: size, 27 - }, 28 - style, 29 - ]} 30 - /> 31 - ); 32 - }
-41
components/ui/icon-symbol.tsx
··· 1 - // Fallback for using MaterialIcons on Android and web. 2 - 3 - import MaterialIcons from '@expo/vector-icons/MaterialIcons'; 4 - import { SymbolWeight, SymbolViewProps } from 'expo-symbols'; 5 - import { ComponentProps } from 'react'; 6 - import { OpaqueColorValue, type StyleProp, type TextStyle } from 'react-native'; 7 - 8 - type IconMapping = Record<SymbolViewProps['name'], ComponentProps<typeof MaterialIcons>['name']>; 9 - type IconSymbolName = keyof typeof MAPPING; 10 - 11 - /** 12 - * Add your SF Symbols to Material Icons mappings here. 13 - * - see Material Icons in the [Icons Directory](https://icons.expo.fyi). 14 - * - see SF Symbols in the [SF Symbols](https://developer.apple.com/sf-symbols/) app. 15 - */ 16 - const MAPPING = { 17 - 'house.fill': 'home', 18 - 'paperplane.fill': 'send', 19 - 'chevron.left.forwardslash.chevron.right': 'code', 20 - 'chevron.right': 'chevron-right', 21 - } as IconMapping; 22 - 23 - /** 24 - * An icon component that uses native SF Symbols on iOS, and Material Icons on Android and web. 25 - * This ensures a consistent look across platforms, and optimal resource usage. 26 - * Icon `name`s are based on SF Symbols and require manual mapping to Material Icons. 27 - */ 28 - export function IconSymbol({ 29 - name, 30 - size = 24, 31 - color, 32 - style, 33 - }: { 34 - name: IconSymbolName; 35 - size?: number; 36 - color: string | OpaqueColorValue; 37 - style?: StyleProp<TextStyle>; 38 - weight?: SymbolWeight; 39 - }) { 40 - return <MaterialIcons color={color} size={size} name={MAPPING[name]} style={style} />; 41 - }
-53
constants/theme.ts
··· 1 - /** 2 - * Below are the colors that are used in the app. The colors are defined in the light and dark mode. 3 - * 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. 4 - */ 5 - 6 - import { Platform } from 'react-native'; 7 - 8 - const tintColorLight = '#0a7ea4'; 9 - const tintColorDark = '#fff'; 10 - 11 - export const Colors = { 12 - light: { 13 - text: '#11181C', 14 - background: '#fff', 15 - tint: tintColorLight, 16 - icon: '#687076', 17 - tabIconDefault: '#687076', 18 - tabIconSelected: tintColorLight, 19 - }, 20 - dark: { 21 - text: '#ECEDEE', 22 - background: '#151718', 23 - tint: tintColorDark, 24 - icon: '#9BA1A6', 25 - tabIconDefault: '#9BA1A6', 26 - tabIconSelected: tintColorDark, 27 - }, 28 - }; 29 - 30 - export const Fonts = Platform.select({ 31 - ios: { 32 - /** iOS `UIFontDescriptorSystemDesignDefault` */ 33 - sans: 'system-ui', 34 - /** iOS `UIFontDescriptorSystemDesignSerif` */ 35 - serif: 'ui-serif', 36 - /** iOS `UIFontDescriptorSystemDesignRounded` */ 37 - rounded: 'ui-rounded', 38 - /** iOS `UIFontDescriptorSystemDesignMonospaced` */ 39 - mono: 'ui-monospace', 40 - }, 41 - default: { 42 - sans: 'normal', 43 - serif: 'serif', 44 - rounded: 'normal', 45 - mono: 'monospace', 46 - }, 47 - web: { 48 - sans: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", 49 - serif: "Georgia, 'Times New Roman', serif", 50 - rounded: "'SF Pro Rounded', 'Hiragino Maru Gothic ProN', Meiryo, 'MS PGothic', sans-serif", 51 - mono: "SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", 52 - }, 53 - });
-1
hooks/use-color-scheme.ts
··· 1 - export { useColorScheme } from 'react-native';
-21
hooks/use-color-scheme.web.ts
··· 1 - import { useEffect, useState } from 'react'; 2 - import { useColorScheme as useRNColorScheme } from 'react-native'; 3 - 4 - /** 5 - * To support static rendering, this value needs to be re-calculated on the client side for web 6 - */ 7 - export function useColorScheme() { 8 - const [hasHydrated, setHasHydrated] = useState(false); 9 - 10 - useEffect(() => { 11 - setHasHydrated(true); 12 - }, []); 13 - 14 - const colorScheme = useRNColorScheme(); 15 - 16 - if (hasHydrated) { 17 - return colorScheme; 18 - } 19 - 20 - return 'light'; 21 - }
-21
hooks/use-theme-color.ts
··· 1 - /** 2 - * Learn more about light and dark modes: 3 - * https://docs.expo.dev/guides/color-schemes/ 4 - */ 5 - 6 - import { Colors } from '@/constants/theme'; 7 - import { useColorScheme } from '@/hooks/use-color-scheme'; 8 - 9 - export function useThemeColor( 10 - props: { light?: string; dark?: string }, 11 - colorName: keyof typeof Colors.light & keyof typeof Colors.dark 12 - ) { 13 - const theme = useColorScheme() ?? 'light'; 14 - const colorFromProps = props[theme]; 15 - 16 - if (colorFromProps) { 17 - return colorFromProps; 18 - } else { 19 - return Colors[theme][colorName]; 20 - } 21 - }
-112
scripts/reset-project.js
··· 1 - #!/usr/bin/env node 2 - 3 - /** 4 - * This script is used to reset the project to a blank state. 5 - * It deletes or moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example based on user input and creates a new /app directory with an index.tsx and _layout.tsx file. 6 - * You can remove the `reset-project` script from package.json and safely delete this file after running it. 7 - */ 8 - 9 - const fs = require("fs"); 10 - const path = require("path"); 11 - const readline = require("readline"); 12 - 13 - const root = process.cwd(); 14 - const oldDirs = ["app", "components", "hooks", "constants", "scripts"]; 15 - const exampleDir = "app-example"; 16 - const newAppDir = "app"; 17 - const exampleDirPath = path.join(root, exampleDir); 18 - 19 - const indexContent = `import { Text, View } from "react-native"; 20 - 21 - export default function Index() { 22 - return ( 23 - <View 24 - style={{ 25 - flex: 1, 26 - justifyContent: "center", 27 - alignItems: "center", 28 - }} 29 - > 30 - <Text>Edit app/index.tsx to edit this screen.</Text> 31 - </View> 32 - ); 33 - } 34 - `; 35 - 36 - const layoutContent = `import { Stack } from "expo-router"; 37 - 38 - export default function RootLayout() { 39 - return <Stack />; 40 - } 41 - `; 42 - 43 - const rl = readline.createInterface({ 44 - input: process.stdin, 45 - output: process.stdout, 46 - }); 47 - 48 - const moveDirectories = async (userInput) => { 49 - try { 50 - if (userInput === "y") { 51 - // Create the app-example directory 52 - await fs.promises.mkdir(exampleDirPath, { recursive: true }); 53 - console.log(`๐Ÿ“ /${exampleDir} directory created.`); 54 - } 55 - 56 - // Move old directories to new app-example directory or delete them 57 - for (const dir of oldDirs) { 58 - const oldDirPath = path.join(root, dir); 59 - if (fs.existsSync(oldDirPath)) { 60 - if (userInput === "y") { 61 - const newDirPath = path.join(root, exampleDir, dir); 62 - await fs.promises.rename(oldDirPath, newDirPath); 63 - console.log(`โžก๏ธ /${dir} moved to /${exampleDir}/${dir}.`); 64 - } else { 65 - await fs.promises.rm(oldDirPath, { recursive: true, force: true }); 66 - console.log(`โŒ /${dir} deleted.`); 67 - } 68 - } else { 69 - console.log(`โžก๏ธ /${dir} does not exist, skipping.`); 70 - } 71 - } 72 - 73 - // Create new /app directory 74 - const newAppDirPath = path.join(root, newAppDir); 75 - await fs.promises.mkdir(newAppDirPath, { recursive: true }); 76 - console.log("\n๐Ÿ“ New /app directory created."); 77 - 78 - // Create index.tsx 79 - const indexPath = path.join(newAppDirPath, "index.tsx"); 80 - await fs.promises.writeFile(indexPath, indexContent); 81 - console.log("๐Ÿ“„ app/index.tsx created."); 82 - 83 - // Create _layout.tsx 84 - const layoutPath = path.join(newAppDirPath, "_layout.tsx"); 85 - await fs.promises.writeFile(layoutPath, layoutContent); 86 - console.log("๐Ÿ“„ app/_layout.tsx created."); 87 - 88 - console.log("\nโœ… Project reset complete. Next steps:"); 89 - console.log( 90 - `1. Run \`npx expo start\` to start a development server.\n2. Edit app/index.tsx to edit the main screen.${ 91 - userInput === "y" 92 - ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.` 93 - : "" 94 - }` 95 - ); 96 - } catch (error) { 97 - console.error(`โŒ Error during script execution: ${error.message}`); 98 - } 99 - }; 100 - 101 - rl.question( 102 - "Do you want to move existing files to /app-example instead of deleting them? (Y/n): ", 103 - (answer) => { 104 - const userInput = answer.trim().toLowerCase() || "y"; 105 - if (userInput === "y" || userInput === "n") { 106 - moveDirectories(userInput).finally(() => rl.close()); 107 - } else { 108 - console.log("โŒ Invalid input. Please enter 'Y' or 'N'."); 109 - rl.close(); 110 - } 111 - } 112 - );