create-better-t-stack 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +52 -38
  2. package/dist/index.js +66 -60
  3. package/package.json +1 -1
  4. package/template/base/apps/native/_gitignore +24 -0
  5. package/template/base/apps/native/app/(drawer)/(tabs)/_layout.tsx +29 -0
  6. package/template/base/apps/native/app/(drawer)/(tabs)/index.tsx +9 -0
  7. package/template/base/apps/native/app/(drawer)/(tabs)/two.tsx +16 -0
  8. package/template/base/apps/native/app/(drawer)/_layout.tsx +39 -0
  9. package/template/base/apps/native/app/(drawer)/index.tsx +36 -0
  10. package/template/base/apps/native/app/+html.tsx +46 -0
  11. package/template/base/apps/native/app/+not-found.tsx +18 -0
  12. package/template/base/apps/native/app/_layout.tsx +76 -0
  13. package/template/base/apps/native/app/modal.tsx +15 -0
  14. package/template/base/apps/native/app-env.d.ts +2 -0
  15. package/template/base/apps/native/app.json +38 -0
  16. package/template/base/apps/native/assets/adaptive-icon.png +0 -0
  17. package/template/base/apps/native/assets/favicon.png +0 -0
  18. package/template/base/apps/native/assets/icon.png +0 -0
  19. package/template/base/apps/native/assets/splash.png +0 -0
  20. package/template/base/apps/native/babel.config.js +12 -0
  21. package/template/base/apps/native/components/container.tsx +9 -0
  22. package/template/base/apps/native/components/header-button.tsx +31 -0
  23. package/template/base/apps/native/components/tabbar-icon.tsx +15 -0
  24. package/template/base/apps/native/global.css +25 -0
  25. package/template/base/apps/native/lib/android-navigation-bar.tsx +11 -0
  26. package/template/base/apps/native/lib/constants.ts +18 -0
  27. package/template/base/apps/native/lib/use-color-scheme.ts +12 -0
  28. package/template/base/apps/native/metro.config.js +57 -0
  29. package/template/base/apps/native/package.json +47 -0
  30. package/template/base/apps/native/tailwind.config.js +32 -0
  31. package/template/base/apps/native/tsconfig.json +18 -0
  32. package/template/base/apps/native/utils/trpc.ts +19 -0
  33. package/template/base/apps/server/package.json +0 -2
  34. package/template/base/apps/server/tsconfig.json +1 -1
  35. package/template/base/apps/{client → web}/package.json +1 -1
  36. package/template/base/apps/web/src/main.tsx +33 -0
  37. package/template/base/apps/{client → web}/src/routes/__root.tsx +3 -3
  38. package/template/base/apps/{client → web}/src/routes/index.tsx +7 -6
  39. package/template/base/apps/web/src/utils/trpc.ts +33 -0
  40. package/template/base/package.json +2 -1
  41. package/template/{with-drizzle-sqlite/apps/server/src/with-auth-lib/context.ts → with-auth/apps/server/src/lib/with-elysia-context.ts} +4 -4
  42. package/template/{with-drizzle-postgres/apps/server/src/with-auth-lib/context.ts → with-auth/apps/server/src/lib/with-hono-context.ts} +3 -3
  43. package/template/with-auth/apps/server/src/with-elysia-index.ts +38 -0
  44. package/template/with-auth/apps/server/src/{index.ts → with-hono-index.ts} +3 -2
  45. package/template/with-auth/apps/{client → web}/src/routes/dashboard.tsx +2 -1
  46. package/template/with-auth/apps/web/src/utils/trpc.ts +39 -0
  47. package/template/with-elysia/apps/server/src/index.ts +27 -0
  48. package/template/with-elysia/apps/server/src/lib/context.ts +13 -0
  49. package/template/{base → with-hono}/apps/server/src/index.ts +2 -2
  50. package/template/{base → with-hono}/apps/server/src/lib/context.ts +2 -2
  51. package/template/base/apps/client/src/main.tsx +0 -72
  52. package/template/base/apps/client/src/utils/trpc.ts +0 -4
  53. package/template/with-auth/apps/client/src/main.tsx +0 -78
  54. package/template/with-drizzle-postgres/apps/server/src/routers/todo.ts +0 -44
  55. package/template/with-drizzle-postgres/apps/server/src/with-auth-lib/trpc.ts +0 -24
  56. package/template/with-drizzle-sqlite/apps/server/src/with-auth-lib/trpc.ts +0 -24
  57. package/template/with-prisma-postgres/apps/server/src/with-auth-lib/context.ts +0 -18
  58. package/template/with-prisma-postgres/apps/server/src/with-auth-lib/trpc.ts +0 -24
  59. package/template/with-prisma-sqlite/apps/server/src/with-auth-lib/context.ts +0 -18
  60. package/template/with-prisma-sqlite/apps/server/src/with-auth-lib/trpc.ts +0 -24
  61. package/template/base/apps/{client → web}/_gitignore +0 -0
  62. package/template/base/apps/{client → web}/components.json +0 -0
  63. package/template/base/apps/{client → web}/index.html +0 -0
  64. package/template/base/apps/{client → web}/src/components/header.tsx +0 -0
  65. package/template/base/apps/{client → web}/src/components/loader.tsx +0 -0
  66. package/template/base/apps/{client → web}/src/components/mode-toggle.tsx +0 -0
  67. package/template/base/apps/{client → web}/src/components/theme-provider.tsx +0 -0
  68. package/template/base/apps/{client → web}/src/components/ui/button.tsx +0 -0
  69. package/template/base/apps/{client → web}/src/components/ui/card.tsx +0 -0
  70. package/template/base/apps/{client → web}/src/components/ui/checkbox.tsx +0 -0
  71. package/template/base/apps/{client → web}/src/components/ui/dropdown-menu.tsx +0 -0
  72. package/template/base/apps/{client → web}/src/components/ui/input.tsx +0 -0
  73. package/template/base/apps/{client → web}/src/components/ui/label.tsx +0 -0
  74. package/template/base/apps/{client → web}/src/components/ui/skeleton.tsx +0 -0
  75. package/template/base/apps/{client → web}/src/components/ui/sonner.tsx +0 -0
  76. package/template/base/apps/{client → web}/src/index.css +0 -0
  77. package/template/base/apps/{client → web}/src/lib/utils.ts +0 -0
  78. package/template/base/apps/{client → web}/tsconfig.json +0 -0
  79. package/template/base/apps/{client → web}/vite.config.ts +0 -0
  80. package/template/examples/todo/apps/{client → web}/src/routes/todos.tsx +0 -0
  81. package/template/{with-drizzle-postgres/apps/server/src/with-auth-lib → with-auth/apps/server/src/with-drizzle-postgres-lib}/auth.ts +1 -1
  82. /package/template/{with-drizzle-sqlite/apps/server/src/with-auth-lib → with-auth/apps/server/src/with-drizzle-sqlite-lib}/auth.ts +0 -0
  83. /package/template/{with-prisma-postgres/apps/server/src/with-auth-lib → with-auth/apps/server/src/with-prisma-postgres-lib}/auth.ts +0 -0
  84. /package/template/{with-prisma-sqlite/apps/server/src/with-auth-lib → with-auth/apps/server/src/with-prisma-sqlite-lib}/auth.ts +0 -0
  85. /package/template/with-auth/apps/{client → web}/src/components/auth-forms.tsx +0 -0
  86. /package/template/with-auth/apps/{client → web}/src/components/header.tsx +0 -0
  87. /package/template/with-auth/apps/{client → web}/src/components/sign-in-form.tsx +0 -0
  88. /package/template/with-auth/apps/{client → web}/src/components/sign-up-form.tsx +0 -0
  89. /package/template/with-auth/apps/{client → web}/src/components/user-menu.tsx +0 -0
  90. /package/template/with-auth/apps/{client → web}/src/lib/auth-client.ts +0 -0
  91. /package/template/with-auth/apps/{client → web}/src/routes/login.tsx +0 -0
  92. /package/template/with-pwa/apps/{client → web}/public/logo.png +0 -0
  93. /package/template/with-pwa/apps/{client → web}/pwa-assets.config.ts +0 -0
  94. /package/template/with-pwa/apps/{client → web}/vite.config.ts +0 -0
@@ -0,0 +1,16 @@
1
+ import { Stack } from "expo-router";
2
+ import { View, Text } from "react-native";
3
+
4
+ import { Container } from "@/components/container";
5
+
6
+ export default function Home() {
7
+ return (
8
+ <>
9
+ <Container>
10
+ <View>
11
+ <Text>Tab Two</Text>
12
+ </View>
13
+ </Container>
14
+ </>
15
+ );
16
+ }
@@ -0,0 +1,39 @@
1
+ import { Ionicons, MaterialIcons } from "@expo/vector-icons";
2
+ import { Link } from "expo-router";
3
+ import { Drawer } from "expo-router/drawer";
4
+
5
+ import { HeaderButton } from "@/components/header-button";
6
+
7
+ const DrawerLayout = () => {
8
+ return (
9
+ <Drawer>
10
+ <Drawer.Screen
11
+ name="index"
12
+ options={{
13
+ headerTitle: "Home",
14
+ drawerLabel: "Home",
15
+ drawerIcon: ({ size, color }) => (
16
+ <Ionicons name="home-outline" size={size} color={color} />
17
+ ),
18
+ }}
19
+ />
20
+ <Drawer.Screen
21
+ name="(tabs)"
22
+ options={{
23
+ headerTitle: "Tabs",
24
+ drawerLabel: "Tabs",
25
+ drawerIcon: ({ size, color }) => (
26
+ <MaterialIcons name="border-bottom" size={size} color={color} />
27
+ ),
28
+ headerRight: () => (
29
+ <Link href="/modal" asChild>
30
+ <HeaderButton />
31
+ </Link>
32
+ ),
33
+ }}
34
+ />
35
+ </Drawer>
36
+ );
37
+ };
38
+
39
+ export default DrawerLayout;
@@ -0,0 +1,36 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { View, Text, ScrollView } from "react-native";
3
+ import { Container } from "@/components/container";
4
+ import { trpc } from "@/utils/trpc";
5
+
6
+ export default function Home() {
7
+ const healthCheck = useQuery(trpc.healthCheck.queryOptions());
8
+
9
+ return (
10
+ <Container>
11
+ <ScrollView className="py-4 flex-1">
12
+ <Text className="font-mono text-foreground text-2xl font-bold mb-6">
13
+ BETTER T STACK
14
+ </Text>
15
+
16
+ <View className="rounded-lg border border-foreground p-4">
17
+ <Text className="mb-2 font-medium text-foreground">API Status</Text>
18
+ <View className="flex-row items-center gap-2">
19
+ <View
20
+ className={`h-2.5 w-2.5 rounded-full ${
21
+ healthCheck.data ? "bg-green-500" : "bg-red-500"
22
+ }`}
23
+ />
24
+ <Text className="text-sm text-foreground">
25
+ {healthCheck.isLoading
26
+ ? "Checking..."
27
+ : healthCheck.data
28
+ ? "Connected"
29
+ : "Disconnected"}
30
+ </Text>
31
+ </View>
32
+ </View>
33
+ </ScrollView>
34
+ </Container>
35
+ );
36
+ }
@@ -0,0 +1,46 @@
1
+ import { ScrollViewStyleReset } from 'expo-router/html';
2
+
3
+ // This file is web-only and used to configure the root HTML for every
4
+ // web page during static rendering.
5
+ // The contents of this function only run in Node.js environments and
6
+ // do not have access to the DOM or browser APIs.
7
+ export default function Root({ children }: { children: React.ReactNode }) {
8
+ return (
9
+ <html lang="en">
10
+ <head>
11
+ <meta charSet="utf-8" />
12
+ <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
13
+
14
+ {/*
15
+ This viewport disables scaling which makes the mobile website act more like a native app.
16
+ However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
17
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
18
+ */}
19
+ <meta
20
+ name="viewport"
21
+ content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
22
+ />
23
+ {/*
24
+ Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
25
+ However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
26
+ */}
27
+ <ScrollViewStyleReset />
28
+
29
+ {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
30
+ <style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
31
+ {/* Add any additional <head> elements that you want globally available on web... */}
32
+ </head>
33
+ <body>{children}</body>
34
+ </html>
35
+ );
36
+ }
37
+
38
+ const responsiveBackground = `
39
+ body {
40
+ background-color: #fff;
41
+ }
42
+ @media (prefers-color-scheme: dark) {
43
+ body {
44
+ background-color: #000;
45
+ }
46
+ }`;
@@ -0,0 +1,18 @@
1
+ import { Link, Stack } from 'expo-router';
2
+ import { Text } from 'react-native';
3
+
4
+ import { Container } from '@/components/container';
5
+
6
+ export default function NotFoundScreen() {
7
+ return (
8
+ <>
9
+ <Stack.Screen options={{ title: 'Oops!' }} />
10
+ <Container>
11
+ <Text className="text-xl font-bold">This screen doesn't exist.</Text>
12
+ <Link href="/" className="mt-4 pt-4">
13
+ <Text className="text-base text-[#2e78b7]">Go to home screen!</Text>
14
+ </Link>
15
+ </Container>
16
+ </>
17
+ );
18
+ }
@@ -0,0 +1,76 @@
1
+ import { QueryClientProvider } from "@tanstack/react-query";
2
+ import { Stack } from "expo-router";
3
+ import {
4
+ DarkTheme,
5
+ DefaultTheme,
6
+ Theme,
7
+ ThemeProvider,
8
+ } from "@react-navigation/native";
9
+ import { StatusBar } from "expo-status-bar";
10
+ import { GestureHandlerRootView } from "react-native-gesture-handler";
11
+ import "../global.css";
12
+ import { queryClient } from "@/utils/trpc";
13
+ import { NAV_THEME } from "@/lib/constants";
14
+ import React, { useRef } from "react";
15
+ import { useColorScheme } from "@/lib/use-color-scheme";
16
+ import { Platform } from "react-native";
17
+ import { setAndroidNavigationBar } from "@/lib/android-navigation-bar";
18
+
19
+ const LIGHT_THEME: Theme = {
20
+ ...DefaultTheme,
21
+ colors: NAV_THEME.light,
22
+ };
23
+ const DARK_THEME: Theme = {
24
+ ...DarkTheme,
25
+ colors: NAV_THEME.dark,
26
+ };
27
+
28
+ export const unstable_settings = {
29
+ // Ensure that reloading on `/modal` keeps a back button present.
30
+ initialRouteName: "(drawer)",
31
+ };
32
+
33
+ export default function RootLayout() {
34
+ const hasMounted = useRef(false);
35
+ const { colorScheme, isDarkColorScheme } = useColorScheme();
36
+ const [isColorSchemeLoaded, setIsColorSchemeLoaded] = React.useState(false);
37
+
38
+ useIsomorphicLayoutEffect(() => {
39
+ if (hasMounted.current) {
40
+ return;
41
+ }
42
+
43
+ if (Platform.OS === "web") {
44
+ // Adds the background color to the html element to prevent white background on overscroll.
45
+ document.documentElement.classList.add("bg-background");
46
+ }
47
+ setAndroidNavigationBar(colorScheme);
48
+ setIsColorSchemeLoaded(true);
49
+ hasMounted.current = true;
50
+ }, []);
51
+
52
+ if (!isColorSchemeLoaded) {
53
+ return null;
54
+ }
55
+ return (
56
+ <QueryClientProvider client={queryClient}>
57
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
58
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
59
+ <GestureHandlerRootView style={{ flex: 1 }}>
60
+ <Stack>
61
+ <Stack.Screen name="(drawer)" options={{ headerShown: false }} />
62
+ <Stack.Screen
63
+ name="modal"
64
+ options={{ title: "Modal", presentation: "modal" }}
65
+ />
66
+ </Stack>
67
+ </GestureHandlerRootView>
68
+ </ThemeProvider>
69
+ </QueryClientProvider>
70
+ );
71
+ }
72
+
73
+ const useIsomorphicLayoutEffect =
74
+ Platform.OS === "web" && typeof window === "undefined"
75
+ ? React.useEffect
76
+ : React.useLayoutEffect;
@@ -0,0 +1,15 @@
1
+ import { Text, View } from "react-native";
2
+
3
+ import { Container } from "@/components/container";
4
+
5
+ export default function Modal() {
6
+ return (
7
+ <>
8
+ <Container>
9
+ <View>
10
+ <Text>HI MODAL</Text>
11
+ </View>
12
+ </Container>
13
+ </>
14
+ );
15
+ }
@@ -0,0 +1,2 @@
1
+ // @ts-ignore
2
+ /// <reference types="nativewind/types" />
@@ -0,0 +1,38 @@
1
+ {
2
+ "expo": {
3
+ "name": "my-better-t-app",
4
+ "slug": "my-better-t-app",
5
+ "version": "1.0.0",
6
+ "scheme": "my-better-t-app",
7
+ "web": {
8
+ "bundler": "metro",
9
+ "output": "static",
10
+ "favicon": "./assets/favicon.png"
11
+ },
12
+ "plugins": ["expo-router"],
13
+ "experiments": {
14
+ "typedRoutes": true,
15
+ "tsconfigPaths": true
16
+ },
17
+ "orientation": "portrait",
18
+ "icon": "./assets/icon.png",
19
+ "userInterfaceStyle": "light",
20
+ "splash": {
21
+ "image": "./assets/splash.png",
22
+ "resizeMode": "contain",
23
+ "backgroundColor": "#ffffff"
24
+ },
25
+ "assetBundlePatterns": ["**/*"],
26
+ "ios": {
27
+ "supportsTablet": true,
28
+ "bundleIdentifier": "com.amanvarshney01.mybettertapp"
29
+ },
30
+ "android": {
31
+ "adaptiveIcon": {
32
+ "foregroundImage": "./assets/adaptive-icon.png",
33
+ "backgroundColor": "#ffffff"
34
+ },
35
+ "package": "com.amanvarshney01.mybettertapp"
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,12 @@
1
+ module.exports = function (api) {
2
+ api.cache(true);
3
+ const plugins = [];
4
+
5
+ plugins.push('react-native-reanimated/plugin');
6
+
7
+ return {
8
+ presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
9
+
10
+ plugins,
11
+ };
12
+ };
@@ -0,0 +1,9 @@
1
+ import { SafeAreaView } from "react-native";
2
+
3
+ export const Container = ({ children }: { children: React.ReactNode }) => {
4
+ return (
5
+ <SafeAreaView className="flex flex-1 p-4 bg-background">
6
+ {children}
7
+ </SafeAreaView>
8
+ );
9
+ };
@@ -0,0 +1,31 @@
1
+ import FontAwesome from '@expo/vector-icons/FontAwesome';
2
+ import { forwardRef } from 'react';
3
+ import { Pressable, StyleSheet } from 'react-native';
4
+
5
+ export const HeaderButton = forwardRef<typeof Pressable, { onPress?: () => void }>(
6
+ ({ onPress }, ref) => {
7
+ return (
8
+ <Pressable onPress={onPress}>
9
+ {({ pressed }) => (
10
+ <FontAwesome
11
+ name="info-circle"
12
+ size={25}
13
+ color="gray"
14
+ style={[
15
+ styles.headerRight,
16
+ {
17
+ opacity: pressed ? 0.5 : 1,
18
+ },
19
+ ]}
20
+ />
21
+ )}
22
+ </Pressable>
23
+ );
24
+ }
25
+ );
26
+
27
+ export const styles = StyleSheet.create({
28
+ headerRight: {
29
+ marginRight: 15,
30
+ },
31
+ });
@@ -0,0 +1,15 @@
1
+ import FontAwesome from '@expo/vector-icons/FontAwesome';
2
+ import { StyleSheet } from 'react-native';
3
+
4
+ export const TabBarIcon = (props: {
5
+ name: React.ComponentProps<typeof FontAwesome>['name'];
6
+ color: string;
7
+ }) => {
8
+ return <FontAwesome size={28} style={styles.tabBarIcon} {...props} />;
9
+ };
10
+
11
+ export const styles = StyleSheet.create({
12
+ tabBarIcon: {
13
+ marginBottom: -3,
14
+ },
15
+ });
@@ -0,0 +1,25 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 100%;
8
+ --foreground: 240 10% 3.9%;
9
+ --primary: 240 5.9% 10%;
10
+ --primary-foreground: 0 0% 98%;
11
+ --secondary: 240 4.8% 95.9%;
12
+ --secondary-foreground: 240 5.9% 10%;
13
+ --destructive: 0 84.2% 60.2%;
14
+ }
15
+
16
+ .dark:root {
17
+ --background: 240 10% 3.9%;
18
+ --foreground: 0 0% 98%;
19
+ --primary: 0 0% 98%;
20
+ --primary-foreground: 240 5.9% 10%;
21
+ --secondary: 240 3.7% 15.9%;
22
+ --secondary-foreground: 0 0% 98%;
23
+ --destructive: 0 72% 51%;
24
+ }
25
+ }
@@ -0,0 +1,11 @@
1
+ import * as NavigationBar from "expo-navigation-bar";
2
+ import { Platform } from "react-native";
3
+ import { NAV_THEME } from "@/lib/constants";
4
+
5
+ export async function setAndroidNavigationBar(theme: "light" | "dark") {
6
+ if (Platform.OS !== "android") return;
7
+ await NavigationBar.setButtonStyleAsync(theme === "dark" ? "light" : "dark");
8
+ await NavigationBar.setBackgroundColorAsync(
9
+ theme === "dark" ? NAV_THEME.dark.background : NAV_THEME.light.background,
10
+ );
11
+ }
@@ -0,0 +1,18 @@
1
+ export const NAV_THEME = {
2
+ light: {
3
+ background: "hsl(0 0% 100%)", // background
4
+ border: "hsl(240 5.9% 90%)", // border
5
+ card: "hsl(0 0% 100%)", // card
6
+ notification: "hsl(0 84.2% 60.2%)", // destructive
7
+ primary: "hsl(240 5.9% 10%)", // primary
8
+ text: "hsl(240 10% 3.9%)", // foreground
9
+ },
10
+ dark: {
11
+ background: "hsl(240 10% 3.9%)", // background
12
+ border: "hsl(240 3.7% 15.9%)", // border
13
+ card: "hsl(240 10% 3.9%)", // card
14
+ notification: "hsl(0 72% 51%)", // destructive
15
+ primary: "hsl(0 0% 98%)", // primary
16
+ text: "hsl(0 0% 98%)", // foreground
17
+ },
18
+ };
@@ -0,0 +1,12 @@
1
+ import { useColorScheme as useNativewindColorScheme } from "nativewind";
2
+
3
+ export function useColorScheme() {
4
+ const { colorScheme, setColorScheme, toggleColorScheme } =
5
+ useNativewindColorScheme();
6
+ return {
7
+ colorScheme: colorScheme ?? "dark",
8
+ isDarkColorScheme: colorScheme === "dark",
9
+ setColorScheme,
10
+ toggleColorScheme,
11
+ };
12
+ }
@@ -0,0 +1,57 @@
1
+ // Learn more https://docs.expo.io/guides/customizing-metro
2
+ const { getDefaultConfig } = require("expo/metro-config");
3
+ const { FileStore } = require("metro-cache");
4
+ const { withNativeWind } = require("nativewind/metro");
5
+ const path = require("path");
6
+
7
+ const config = withTurborepoManagedCache(
8
+ withMonorepoPaths(
9
+ withNativeWind(getDefaultConfig(__dirname), {
10
+ input: "./global.css",
11
+ configPath: "./tailwind.config.js",
12
+ }),
13
+ ),
14
+ );
15
+
16
+ config.resolver.unstable_enablePackageExports = true;
17
+
18
+ module.exports = config;
19
+
20
+ /**
21
+ * Add the monorepo paths to the Metro config.
22
+ * This allows Metro to resolve modules from the monorepo.
23
+ *
24
+ * @see https://docs.expo.dev/guides/monorepos/#modify-the-metro-config
25
+ * @param {import('expo/metro-config').MetroConfig} config
26
+ * @returns {import('expo/metro-config').MetroConfig}
27
+ */
28
+ function withMonorepoPaths(config) {
29
+ const projectRoot = __dirname;
30
+ const workspaceRoot = path.resolve(projectRoot, "../..");
31
+
32
+ // #1 - Watch all files in the monorepo
33
+ config.watchFolders = [workspaceRoot];
34
+
35
+ // #2 - Resolve modules within the project's `node_modules` first, then all monorepo modules
36
+ config.resolver.nodeModulesPaths = [
37
+ path.resolve(projectRoot, "node_modules"),
38
+ path.resolve(workspaceRoot, "node_modules"),
39
+ ];
40
+
41
+ return config;
42
+ }
43
+
44
+ /**
45
+ * Move the Metro cache to the `.cache/metro` folder.
46
+ * If you have any environment variables, you can configure Turborepo to invalidate it when needed.
47
+ *
48
+ * @see https://turbo.build/repo/docs/reference/configuration#env
49
+ * @param {import('expo/metro-config').MetroConfig} config
50
+ * @returns {import('expo/metro-config').MetroConfig}
51
+ */
52
+ function withTurborepoManagedCache(config) {
53
+ config.cacheStores = [
54
+ new FileStore({ root: path.join(__dirname, ".cache/metro") }),
55
+ ];
56
+ return config;
57
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "native",
3
+ "version": "1.0.0",
4
+ "main": "expo-router/entry",
5
+ "scripts": {
6
+ "dev": "expo start",
7
+ "android": "expo run:android",
8
+ "ios": "expo run:ios",
9
+ "prebuild": "expo prebuild",
10
+ "web": "expo start --web"
11
+ },
12
+ "dependencies": {
13
+ "@expo/vector-icons": "^14.0.4",
14
+ "@react-navigation/bottom-tabs": "^7.2.0",
15
+ "@react-navigation/drawer": "^7.1.1",
16
+ "@react-navigation/native": "^7.0.14",
17
+ "@tanstack/react-form": "^1.0.5",
18
+ "@tanstack/react-query": "^5.69.2",
19
+ "@trpc/client": "^11.0.0",
20
+ "@trpc/server": "^11.0.0",
21
+ "@trpc/tanstack-react-query": "^11.0.0",
22
+ "expo": "^52.0.41",
23
+ "expo-constants": "~17.0.8",
24
+ "expo-linking": "~7.0.5",
25
+ "expo-navigation-bar": "~4.0.8",
26
+ "expo-router": "~4.0.19",
27
+ "expo-status-bar": "~2.0.1",
28
+ "expo-system-ui": "~4.0.8",
29
+ "expo-web-browser": "~14.0.2",
30
+ "nativewind": "^4.1.23",
31
+ "react": "18.3.1",
32
+ "react-dom": "18.3.1",
33
+ "react-native": "0.76.7",
34
+ "react-native-gesture-handler": "~2.20.2",
35
+ "react-native-reanimated": "3.16.2",
36
+ "react-native-safe-area-context": "4.12.0",
37
+ "react-native-screens": "~4.4.0",
38
+ "react-native-web": "~0.19.13"
39
+ },
40
+ "devDependencies": {
41
+ "@babel/core": "^7.26.10",
42
+ "@types/react": "~18.3.12",
43
+ "tailwindcss": "^3.4.17",
44
+ "typescript": "~5.8.2"
45
+ },
46
+ "private": true
47
+ }
@@ -0,0 +1,32 @@
1
+ const { hairlineWidth } = require("nativewind/theme");
2
+
3
+ /** @type {import('tailwindcss').Config} */
4
+ module.exports = {
5
+ darkMode: "class",
6
+ content: ["./app/**/*.{js,ts,tsx}", "./components/**/*.{js,ts,tsx}"],
7
+
8
+ presets: [require("nativewind/preset")],
9
+ theme: {
10
+ extend: {
11
+ colors: {
12
+ background: "hsl(var(--background))",
13
+ foreground: "hsl(var(--foreground))",
14
+ primary: {
15
+ DEFAULT: "hsl(var(--primary))",
16
+ foreground: "hsl(var(--primary-foreground))",
17
+ },
18
+ secondary: {
19
+ DEFAULT: "hsl(var(--secondary))",
20
+ foreground: "hsl(var(--secondary-foreground))",
21
+ },
22
+ destructive: {
23
+ DEFAULT: "hsl(var(--destructive))",
24
+ },
25
+ },
26
+ borderWidth: {
27
+ hairline: hairlineWidth(),
28
+ },
29
+ },
30
+ },
31
+ plugins: [],
32
+ };
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "paths": {
6
+ "@/*": [
7
+ "./*"
8
+ ]
9
+ }
10
+ },
11
+ "include": [
12
+ "**/*.ts",
13
+ "**/*.tsx",
14
+ ".expo/types/**/*.ts",
15
+ "expo-env.d.ts",
16
+ "nativewind-env.d.ts"
17
+ ]
18
+ }
@@ -0,0 +1,19 @@
1
+ import type { AppRouter } from "../../server/src/routers";
2
+ import { QueryClient } from "@tanstack/react-query";
3
+ import { createTRPCClient, httpBatchLink } from "@trpc/client";
4
+ import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
5
+
6
+ export const queryClient = new QueryClient();
7
+
8
+ const trpcClient = createTRPCClient<AppRouter>({
9
+ links: [
10
+ httpBatchLink({
11
+ url: `${process.env.EXPO_PUBLIC_SERVER_URL}/trpc`,
12
+ }),
13
+ ],
14
+ });
15
+
16
+ export const trpc = createTRPCOptionsProxy<AppRouter>({
17
+ client: trpcClient,
18
+ queryClient,
19
+ });
@@ -8,10 +8,8 @@
8
8
  "compile": "bun build --compile --minify --sourcemap --bytecode ./src/index.ts --outfile server"
9
9
  },
10
10
  "dependencies": {
11
- "@hono/trpc-server": "^0.3.4",
12
11
  "@trpc/server": "^11.0.0",
13
12
  "dotenv": "^16.4.7",
14
- "hono": "^4.7.5",
15
13
  "zod": "^3.24.2"
16
14
  },
17
15
  "devDependencies": {
@@ -8,7 +8,7 @@
8
8
  "skipLibCheck": true,
9
9
  "baseUrl": "./",
10
10
  "outDir": "./dist",
11
- "types": ["node"],
11
+ "types": ["node", "bun"],
12
12
  "jsx": "react-jsx",
13
13
  "jsxImportSource": "hono/jsx"
14
14
  },
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "client",
2
+ "name": "web",
3
3
  "version": "0.0.0",
4
4
  "private": true,
5
5
  "type": "module",