initial commit

This commit is contained in:
René Schober
2026-03-13 06:23:06 +01:00
commit 4e34270786
314 changed files with 37280 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
import { Ionicons } from "@expo/vector-icons";
import { Tabs } from "expo-router";
import { useThemeColor } from "heroui-native";
export default function TabLayout() {
const themeColorForeground = useThemeColor("foreground");
const themeColorBackground = useThemeColor("background");
return (
<Tabs
screenOptions={{
headerShown: false,
headerStyle: {
backgroundColor: themeColorBackground,
},
headerTintColor: themeColorForeground,
headerTitleStyle: {
color: themeColorForeground,
fontWeight: "600",
},
tabBarStyle: {
backgroundColor: themeColorBackground,
},
}}
>
<Tabs.Screen
name="index"
options={{
title: "Home",
tabBarIcon: ({ color, size }: { color: string; size: number }) => (
<Ionicons name="home" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="two"
options={{
title: "Explore",
tabBarIcon: ({ color, size }: { color: string; size: number }) => (
<Ionicons name="compass" size={size} color={color} />
),
}}
/>
</Tabs>
);
}

View File

@@ -0,0 +1,16 @@
import { Card } from "heroui-native";
import { Text, View } from "react-native";
import { Container } from "@/components/container";
export default function Home() {
return (
<Container className="p-6">
<View className="flex-1 justify-center items-center">
<Card variant="secondary" className="p-8 items-center">
<Card.Title className="text-3xl mb-2">Tab One</Card.Title>
</Card>
</View>
</Container>
);
}

View File

@@ -0,0 +1,16 @@
import { Card } from "heroui-native";
import { Text, View } from "react-native";
import { Container } from "@/components/container";
export default function TabTwo() {
return (
<Container className="p-6">
<View className="flex-1 justify-center items-center">
<Card variant="secondary" className="p-8 items-center">
<Card.Title className="text-3xl mb-2">TabTwo</Card.Title>
</Card>
</View>
</Container>
);
}

View File

@@ -0,0 +1,72 @@
import { Ionicons, MaterialIcons } from "@expo/vector-icons";
import { Link } from "expo-router";
import { Drawer } from "expo-router/drawer";
import { useThemeColor } from "heroui-native";
import React, { useCallback } from "react";
import { Pressable, Text } from "react-native";
import { ThemeToggle } from "@/components/theme-toggle";
function DrawerLayout() {
const themeColorForeground = useThemeColor("foreground");
const themeColorBackground = useThemeColor("background");
const renderThemeToggle = useCallback(() => <ThemeToggle />, []);
return (
<Drawer
screenOptions={{
headerTintColor: themeColorForeground,
headerStyle: { backgroundColor: themeColorBackground },
headerTitleStyle: {
fontWeight: "600",
color: themeColorForeground,
},
headerRight: renderThemeToggle,
drawerStyle: { backgroundColor: themeColorBackground },
}}
>
<Drawer.Screen
name="index"
options={{
headerTitle: "Home",
drawerLabel: ({ color, focused }) => (
<Text style={{ color: focused ? color : themeColorForeground }}>Home</Text>
),
drawerIcon: ({ size, color, focused }) => (
<Ionicons
name="home-outline"
size={size}
color={focused ? color : themeColorForeground}
/>
),
}}
/>
<Drawer.Screen
name="(tabs)"
options={{
headerTitle: "Tabs",
drawerLabel: ({ color, focused }) => (
<Text style={{ color: focused ? color : themeColorForeground }}>Tabs</Text>
),
drawerIcon: ({ size, color, focused }) => (
<MaterialIcons
name="border-bottom"
size={size}
color={focused ? color : themeColorForeground}
/>
),
headerRight: () => (
<Link href="/modal" asChild>
<Pressable className="mr-4">
<Ionicons name="add-outline" size={24} color={themeColorForeground} />
</Pressable>
</Link>
),
}}
/>
</Drawer>
);
}
export default DrawerLayout;

View File

@@ -0,0 +1,49 @@
import { Ionicons } from "@expo/vector-icons";
import { Card, Chip, useThemeColor } from "heroui-native";
import { Text, View, Pressable } from "react-native";
import { Container } from "@/components/container";
import { SignIn } from "@/components/sign-in";
import { SignUp } from "@/components/sign-up";
import { authClient } from "@/lib/auth-client";
export default function Home() {
const { data: session } = authClient.useSession();
const mutedColor = useThemeColor("muted");
const successColor = useThemeColor("success");
const dangerColor = useThemeColor("danger");
const foregroundColor = useThemeColor("foreground");
return (
<Container className="p-6">
<View className="py-4 mb-6">
<Text className="text-4xl font-bold text-foreground mb-2">BETTER T STACK</Text>
</View>
{session?.user ? (
<Card variant="secondary" className="mb-6 p-4">
<Text className="text-foreground text-base mb-2">
Welcome, <Text className="font-medium">{session.user.name}</Text>
</Text>
<Text className="text-muted text-sm mb-4">{session.user.email}</Text>
<Pressable
className="bg-danger py-3 px-4 rounded-lg self-start active:opacity-70"
onPress={() => {
authClient.signOut();
}}
>
<Text className="text-foreground font-medium">Sign Out</Text>
</Pressable>
</Card>
) : null}
{!session?.user && (
<>
<SignIn />
<SignUp />
</>
)}
</Container>
);
}

View File

@@ -0,0 +1,27 @@
import { Link, Stack } from "expo-router";
import { Button, Surface } from "heroui-native";
import { Text, View } from "react-native";
import { Container } from "@/components/container";
export default function NotFoundScreen() {
return (
<>
<Stack.Screen options={{ title: "Not Found" }} />
<Container>
<View className="flex-1 justify-center items-center p-4">
<Surface variant="secondary" className="items-center p-6 max-w-sm rounded-lg">
<Text className="text-4xl mb-3">🤔</Text>
<Text className="text-foreground font-medium text-lg mb-1">Page Not Found</Text>
<Text className="text-muted text-sm text-center mb-4">
The page you're looking for doesn't exist.
</Text>
<Link href="/" asChild>
<Button size="sm">Go Home</Button>
</Link>
</Surface>
</View>
</Container>
</>
);
}

View File

@@ -0,0 +1,34 @@
import "@/global.css";
import { Stack } from "expo-router";
import { HeroUINativeProvider } from "heroui-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { KeyboardProvider } from "react-native-keyboard-controller";
import { AppThemeProvider } from "@/contexts/app-theme-context";
export const unstable_settings = {
initialRouteName: "(drawer)",
};
function StackLayout() {
return (
<Stack screenOptions={{}}>
<Stack.Screen name="(drawer)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ title: "Modal", presentation: "modal" }} />
</Stack>
);
}
export default function Layout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<KeyboardProvider>
<AppThemeProvider>
<HeroUINativeProvider>
<StackLayout />
</HeroUINativeProvider>
</AppThemeProvider>
</KeyboardProvider>
</GestureHandlerRootView>
);
}

37
apps/native/app/modal.tsx Normal file
View File

@@ -0,0 +1,37 @@
import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router";
import { Button, Surface, useThemeColor } from "heroui-native";
import { Text, View } from "react-native";
import { Container } from "@/components/container";
function Modal() {
const accentForegroundColor = useThemeColor("accent-foreground");
function handleClose() {
router.back();
}
return (
<Container>
<View className="flex-1 justify-center items-center p-4">
<Surface variant="secondary" className="p-5 w-full max-w-sm rounded-lg">
<View className="items-center">
<View className="w-12 h-12 bg-accent rounded-lg items-center justify-center mb-3">
<Ionicons name="checkmark" size={24} color={accentForegroundColor} />
</View>
<Text className="text-foreground font-medium text-lg mb-1">Modal Screen</Text>
<Text className="text-muted text-sm text-center mb-4">
This is an example modal screen for dialogs and confirmations.
</Text>
</View>
<Button onPress={handleClose} className="w-full" size="sm">
<Button.Label>Close</Button.Label>
</Button>
</Surface>
</View>
</Container>
);
}
export default Modal;