native bottom tab

This commit is contained in:
EthanShoeDev
2025-09-15 00:42:49 -04:00
parent 2078b022ea
commit 89cb6c4b6b
5 changed files with 50 additions and 11 deletions

View File

@@ -1,11 +1,24 @@
import { QueryClientProvider } from '@tanstack/react-query';
import { Stack } from 'expo-router';
import { NativeTabs, Icon, Label } from 'expo-router/unstable-native-tabs';
import { queryClient } from '../lib/utils';
export default function RootLayout() {
return (
<QueryClientProvider client={queryClient}>
<Stack screenOptions={{ headerShown: false }} />
<NativeTabs>
<NativeTabs.Trigger name="index">
<Label>Host</Label>
<Icon sf="house.fill" drawable="custom_android_drawable" />
</NativeTabs.Trigger>
<NativeTabs.Trigger name="shell">
<Icon sf="gear" drawable="custom_settings_drawable" />
<Label>Shell</Label>
</NativeTabs.Trigger>
<NativeTabs.Trigger name="settings">
<Icon sf="gear" drawable="custom_settings_drawable" />
<Label>Settings</Label>
</NativeTabs.Trigger>
</NativeTabs>
</QueryClientProvider>
);
}

View File

@@ -5,6 +5,7 @@ import { useMutation, useQuery } from '@tanstack/react-query';
import { useRouter } from 'expo-router';
import React from 'react';
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { AbortSignalTimeout } from '@/lib/utils';
import { useAppForm, useFieldContext } from '../components/form-components';
import { KeyManagerModal } from '../components/key-manager-modal';
@@ -104,7 +105,7 @@ export default function Index() {
);
return (
<View style={styles.container}>
<SafeAreaView style={styles.container}>
<ScrollView
contentContainerStyle={styles.scrollContent}
keyboardShouldPersistTaps="handled"
@@ -218,7 +219,7 @@ export default function Index() {
}}
/>
</ScrollView>
</View>
</SafeAreaView>
);
}

View File

@@ -0,0 +1,17 @@
import { View, Text, StyleSheet } from 'react-native';
export default function Tab() {
return (
<View style={styles.container}>
<Text>Tab [Home|Settings]</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});

View File

@@ -5,9 +5,9 @@ export const queryClient = new QueryClient();
export type StrictOmit<T, K extends keyof T> = Omit<T, K>;
export const AbortSignalTimeout = (timeout: number) => {
// AbortSignal.timeout is not available as of expo 54
// TypeError: AbortSignal.timeout is not a function (it is undefined)
const controller = new AbortController();
setTimeout(() => controller.abort(), timeout);
return controller.signal;
}
// AbortSignal.timeout is not available as of expo 54
// TypeError: AbortSignal.timeout is not a function (it is undefined)
const controller = new AbortController();
setTimeout(() => controller.abort(), timeout);
return controller.signal;
};