mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
add unistyles
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { Tabs } from "expo-router";
|
||||
import { useUnistyles } from "react-native-unistyles";
|
||||
|
||||
import { TabBarIcon } from "@/components/tabbar-icon";
|
||||
|
||||
export default function TabLayout() {
|
||||
const { theme } = useUnistyles();
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
title: "Tab One",
|
||||
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="two"
|
||||
options={{
|
||||
title: "Tab Two",
|
||||
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Stack } from "expo-router";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { Container } from "@/components/container";
|
||||
import { Text, View } from "react-native";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Tab One" }} />
|
||||
<Container>
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>Tab One</Text>
|
||||
</View>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
text: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: 100,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Stack } from "expo-router";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { Container } from "@/components/container";
|
||||
import { Text, View } from "react-native";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Tab Two" }} />
|
||||
<Container>
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>Tab Two</Text>
|
||||
</View>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
text: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: 100,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Ionicons, MaterialIcons } from "@expo/vector-icons";
|
||||
import { Link } from "expo-router";
|
||||
import { Drawer } from "expo-router/drawer";
|
||||
import { useUnistyles } from "react-native-unistyles";
|
||||
|
||||
import { HeaderButton } from "../../components/header-button";
|
||||
|
||||
const DrawerLayout = () => {
|
||||
const { theme } = useUnistyles();
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
screenOptions={{
|
||||
headerStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
headerTintColor: theme.colors.typography,
|
||||
drawerStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
drawerLabelStyle: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
drawerInactiveTintColor: theme.colors.typography,
|
||||
}}
|
||||
>
|
||||
<Drawer.Screen
|
||||
name="index"
|
||||
options={{
|
||||
headerTitle: "Home",
|
||||
drawerLabel: "Home",
|
||||
drawerIcon: ({ size, color }) => (
|
||||
<Ionicons name="home-outline" size={size} color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Drawer.Screen
|
||||
name="(tabs)"
|
||||
options={{
|
||||
headerTitle: "Tabs",
|
||||
drawerLabel: "Tabs",
|
||||
drawerIcon: ({ size, color }) => (
|
||||
<MaterialIcons name="border-bottom" size={size} color={color} />
|
||||
),
|
||||
headerRight: () => (
|
||||
<Link href="/modal" asChild>
|
||||
<HeaderButton />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default DrawerLayout;
|
||||
@@ -0,0 +1,115 @@
|
||||
import { ScrollView, Text, View } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { Container } from "@/components/container";
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { orpc } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { trpc } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
import { useQuery } from "convex/react";
|
||||
import { api } from "@{{ projectName }}/backend/convex/_generated/api.js";
|
||||
{{/if}}
|
||||
|
||||
export default function Home() {
|
||||
{{#if (eq api "orpc")}}
|
||||
const healthCheck = useQuery(orpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
const healthCheck = useQuery(trpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
const healthCheck = useQuery(api.healthCheck.get);
|
||||
{{/if}}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<ScrollView contentContainerStyle={styles.pageContainer}>
|
||||
<Text style={styles.headerTitle}>BETTER T STACK</Text>
|
||||
|
||||
<View style={styles.apiStatusCard}>
|
||||
<Text style={styles.cardTitle}>API Status</Text>
|
||||
<View style={styles.apiStatusRow}>
|
||||
<View
|
||||
style={[
|
||||
styles.statusIndicatorDot,
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
healthCheck.data
|
||||
? styles.statusIndicatorGreen
|
||||
: styles.statusIndicatorRed,
|
||||
{{else}}
|
||||
healthCheck === "OK"
|
||||
? styles.statusIndicatorGreen
|
||||
: styles.statusIndicatorRed,
|
||||
{{/if}}
|
||||
]}
|
||||
/>
|
||||
<Text style={styles.statusText}>
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
{healthCheck === undefined
|
||||
? "Checking..."
|
||||
: healthCheck === "OK"
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
{{/if}}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
pageContainer: {
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
headerTitle: {
|
||||
color: theme?.colors?.typography,
|
||||
fontSize: 30,
|
||||
fontWeight: "bold",
|
||||
marginBottom: 16,
|
||||
},
|
||||
apiStatusCard: {
|
||||
marginBottom: 24,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: theme?.colors?.border,
|
||||
padding: 16,
|
||||
},
|
||||
cardTitle: {
|
||||
marginBottom: 12,
|
||||
fontWeight: "500",
|
||||
color: theme?.colors?.typography,
|
||||
},
|
||||
apiStatusRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
},
|
||||
statusIndicatorDot: {
|
||||
height: 12,
|
||||
width: 12,
|
||||
borderRadius: 9999,
|
||||
},
|
||||
statusIndicatorGreen: {
|
||||
backgroundColor: theme.colors.success,
|
||||
},
|
||||
statusIndicatorRed: {
|
||||
backgroundColor: theme.colors.destructive,
|
||||
},
|
||||
statusText: {
|
||||
color: theme?.colors?.typography,
|
||||
},
|
||||
}));
|
||||
48
apps/cli/templates/frontend/native/unistyles/app/+html.tsx
Normal file
48
apps/cli/templates/frontend/native/unistyles/app/+html.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { ScrollViewStyleReset } from 'expo-router/html';
|
||||
|
||||
import '../unistyles';
|
||||
|
||||
// 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" />
|
||||
|
||||
{/*
|
||||
This viewport disables scaling which makes the mobile website act more like a native app.
|
||||
However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
*/}
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
|
||||
/>
|
||||
{/*
|
||||
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,34 @@
|
||||
import { Link, Stack } from "expo-router";
|
||||
import { Text } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
|
||||
import { Container } from "@/components/container";
|
||||
|
||||
export default function NotFoundScreen() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Oops!" }} />
|
||||
<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>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: "bold",
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
link: {
|
||||
marginTop: 16,
|
||||
paddingVertical: 16,
|
||||
},
|
||||
linkText: {
|
||||
fontSize: 14,
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,77 @@
|
||||
{{#if (eq api "trpc")}}
|
||||
import { queryClient } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
import { queryClient } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
{{else}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
{{/if}}
|
||||
import { Stack } from "expo-router";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { useUnistyles } from "react-native-unistyles";
|
||||
|
||||
export const unstable_settings = {
|
||||
// Ensure that reloading on `/modal` keeps a back button present.
|
||||
initialRouteName: "(drawer)",
|
||||
};
|
||||
|
||||
{{#if (eq backend "convex")}}
|
||||
const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, {
|
||||
unsavedChangesWarning: false,
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
export default function RootLayout() {
|
||||
const { theme } = useUnistyles();
|
||||
|
||||
return (
|
||||
{{#if (eq backend "convex")}}
|
||||
<ConvexProvider client={convex}>
|
||||
<GestureHandlerRootView style=\{{ flex: 1 }}>
|
||||
<Stack
|
||||
screenOptions=\{{
|
||||
headerStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
headerTintColor: theme.colors.typography,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="modal"
|
||||
options=\{{ title: "Modal", presentation: "modal" }}
|
||||
/>
|
||||
</Stack>
|
||||
</GestureHandlerRootView>
|
||||
</ConvexProvider>
|
||||
{{else}}
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<GestureHandlerRootView style=\{{ flex: 1 }}>
|
||||
<Stack
|
||||
screenOptions=\{{
|
||||
headerStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
headerTintColor: theme.colors.typography,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="modal"
|
||||
options=\{{ title: "Modal", presentation: "modal" }}
|
||||
/>
|
||||
</Stack>
|
||||
</GestureHandlerRootView>
|
||||
</QueryClientProvider>
|
||||
{{/if}}
|
||||
);
|
||||
}
|
||||
29
apps/cli/templates/frontend/native/unistyles/app/modal.tsx
Normal file
29
apps/cli/templates/frontend/native/unistyles/app/modal.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Container } from "@/components/container";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { Platform, Text, View } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
|
||||
export default function Modal() {
|
||||
return (
|
||||
<>
|
||||
<StatusBar style={Platform.OS === "ios" ? "light" : "auto"} />
|
||||
<Container>
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>Model</Text>
|
||||
</View>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
text: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: 100,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user