create-better-t-stack 3.2.23 → 3.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.
- package/README.md +2 -2
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/{src-Cx7HDf0b.js → src-82W1Q-C5.js} +82 -54
- package/package.json +1 -1
- package/templates/addons/biome/biome.json.hbs +5 -0
- package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +5 -5
- package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +1 -1
- package/templates/auth/better-auth/convex/native/bare/components/sign-in.tsx.hbs +127 -0
- package/templates/auth/better-auth/convex/native/bare/components/sign-up.tsx.hbs +138 -0
- package/templates/auth/better-auth/convex/native/uniwind/components/sign-in.tsx.hbs +91 -0
- package/templates/auth/better-auth/convex/native/uniwind/components/sign-up.tsx.hbs +102 -0
- package/templates/auth/better-auth/native/bare/app/(drawer)/index.tsx.hbs +186 -0
- package/templates/auth/better-auth/native/bare/components/sign-in.tsx.hbs +131 -0
- package/templates/auth/better-auth/native/bare/components/sign-up.tsx.hbs +150 -0
- package/templates/auth/better-auth/native/unistyles/app/(drawer)/index.tsx.hbs +9 -1
- package/templates/auth/better-auth/native/unistyles/components/sign-in.tsx.hbs +5 -0
- package/templates/auth/better-auth/native/unistyles/components/sign-up.tsx.hbs +5 -0
- package/templates/auth/better-auth/native/uniwind/app/(drawer)/index.tsx.hbs +123 -0
- package/templates/auth/better-auth/native/uniwind/components/sign-in.tsx.hbs +90 -0
- package/templates/auth/better-auth/native/uniwind/components/sign-up.tsx.hbs +116 -0
- package/templates/auth/better-auth/server/base/src/index.ts.hbs +5 -5
- package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +287 -0
- package/templates/examples/ai/native/{nativewind → bare}/polyfills.js +1 -0
- package/templates/examples/ai/native/{nativewind → uniwind}/app/(drawer)/ai.tsx.hbs +52 -51
- package/templates/examples/ai/native/uniwind/polyfills.js +26 -0
- package/templates/examples/todo/native/bare/app/(drawer)/todos.tsx.hbs +521 -0
- package/templates/examples/todo/native/uniwind/app/(drawer)/todos.tsx.hbs +295 -0
- package/templates/extras/bunfig.toml.hbs +3 -3
- package/templates/frontend/native/bare/_gitignore +18 -0
- package/templates/frontend/native/{nativewind → bare}/app/(drawer)/(tabs)/_layout.tsx.hbs +7 -12
- package/templates/frontend/native/bare/app/(drawer)/(tabs)/index.tsx.hbs +43 -0
- package/templates/frontend/native/bare/app/(drawer)/(tabs)/two.tsx.hbs +43 -0
- package/templates/frontend/native/{nativewind → bare}/app/(drawer)/_layout.tsx.hbs +24 -1
- package/templates/frontend/native/bare/app/(drawer)/index.tsx.hbs +234 -0
- package/templates/frontend/native/bare/app/+not-found.tsx.hbs +65 -0
- package/templates/frontend/native/bare/app/_layout.tsx.hbs +163 -0
- package/templates/frontend/native/bare/app/modal.tsx.hbs +34 -0
- package/templates/frontend/native/{nativewind → bare}/app.json.hbs +1 -0
- package/templates/frontend/native/bare/components/container.tsx.hbs +25 -0
- package/templates/frontend/native/bare/components/header-button.tsx.hbs +47 -0
- package/templates/frontend/native/{nativewind → bare}/components/tabbar-icon.tsx.hbs +1 -0
- package/templates/frontend/native/{nativewind → bare}/lib/android-navigation-bar.tsx.hbs +1 -0
- package/templates/frontend/native/{nativewind → bare}/lib/constants.ts.hbs +1 -0
- package/templates/frontend/native/bare/lib/use-color-scheme.ts.hbs +20 -0
- package/templates/frontend/native/bare/metro.config.js.hbs +9 -0
- package/templates/frontend/native/{nativewind → bare}/package.json.hbs +1 -2
- package/templates/frontend/native/bare/tsconfig.json.hbs +11 -0
- package/templates/frontend/native/{nativewind → uniwind}/_gitignore +4 -8
- package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/_layout.tsx.hbs +46 -0
- package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/index.tsx.hbs +15 -0
- package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/two.tsx.hbs +15 -0
- package/templates/frontend/native/uniwind/app/(drawer)/_layout.tsx.hbs +83 -0
- package/templates/frontend/native/uniwind/app/(drawer)/index.tsx.hbs +151 -0
- package/templates/frontend/native/uniwind/app/+not-found.tsx.hbs +32 -0
- package/templates/frontend/native/uniwind/app/_layout.tsx.hbs +131 -0
- package/templates/frontend/native/uniwind/app/modal.tsx.hbs +53 -0
- package/templates/frontend/native/uniwind/app.json.hbs +19 -0
- package/templates/frontend/native/uniwind/components/container.tsx.hbs +33 -0
- package/templates/frontend/native/uniwind/components/theme-toggle.tsx.hbs +35 -0
- package/templates/frontend/native/uniwind/contexts/app-theme-context.tsx.hbs +62 -0
- package/templates/frontend/native/uniwind/global.css +5 -0
- package/templates/frontend/native/uniwind/metro.config.js.hbs +13 -0
- package/templates/frontend/native/uniwind/package.json.hbs +54 -0
- package/templates/frontend/native/{nativewind → uniwind}/tsconfig.json.hbs +4 -8
- package/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs +0 -86
- package/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs +0 -97
- package/templates/auth/better-auth/native/nativewind/app/(drawer)/index.tsx.hbs +0 -95
- package/templates/auth/better-auth/native/nativewind/components/sign-in.tsx.hbs +0 -93
- package/templates/auth/better-auth/native/nativewind/components/sign-up.tsx.hbs +0 -104
- package/templates/examples/todo/native/nativewind/app/(drawer)/todos.tsx.hbs +0 -295
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/index.tsx.hbs +0 -19
- package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/two.tsx.hbs +0 -19
- package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +0 -178
- package/templates/frontend/native/nativewind/app/+not-found.tsx.hbs +0 -29
- package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +0 -175
- package/templates/frontend/native/nativewind/app/modal.tsx.hbs +0 -14
- package/templates/frontend/native/nativewind/babel.config.js.hbs +0 -14
- package/templates/frontend/native/nativewind/components/container.tsx.hbs +0 -8
- package/templates/frontend/native/nativewind/components/header-button.tsx.hbs +0 -26
- package/templates/frontend/native/nativewind/global.css +0 -50
- package/templates/frontend/native/nativewind/lib/use-color-scheme.ts.hbs +0 -12
- package/templates/frontend/native/nativewind/metro.config.js.hbs +0 -12
- package/templates/frontend/native/nativewind/tailwind.config.js.hbs +0 -59
- /package/templates/auth/clerk/convex/native/base/app/(auth)/{sign-out.tsx.hbs → sign-up.tsx.hbs} +0 -0
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ Options:
|
|
|
57
57
|
--orm <type> ORM type (none, drizzle, prisma, mongoose)
|
|
58
58
|
--auth Include authentication
|
|
59
59
|
--no-auth Exclude authentication
|
|
60
|
-
--frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-
|
|
60
|
+
--frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-bare, native-uniwind, native-unistyles, none)
|
|
61
61
|
--addons <types...> Additional addons (pwa, tauri, starlight, biome, husky, turborepo, fumadocs, ultracite, oxlint, none)
|
|
62
62
|
--examples <types...> Examples to include (todo, ai, none)
|
|
63
63
|
--git Initialize git repository
|
|
@@ -119,7 +119,7 @@ npx create-better-t-stack my-app --backend elysia --runtime node
|
|
|
119
119
|
Create a project with multiple frontend options (one web + one native):
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
npx create-better-t-stack my-app --frontend tanstack-router native-
|
|
122
|
+
npx create-better-t-stack my-app --frontend tanstack-router native-bare
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
Create a project with examples:
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -43,7 +43,8 @@ declare const FrontendSchema: z.ZodEnum<{
|
|
|
43
43
|
"tanstack-start": "tanstack-start";
|
|
44
44
|
next: "next";
|
|
45
45
|
nuxt: "nuxt";
|
|
46
|
-
"native-
|
|
46
|
+
"native-bare": "native-bare";
|
|
47
|
+
"native-uniwind": "native-uniwind";
|
|
47
48
|
"native-unistyles": "native-unistyles";
|
|
48
49
|
svelte: "svelte";
|
|
49
50
|
solid: "solid";
|
|
@@ -242,7 +243,8 @@ declare const router: {
|
|
|
242
243
|
"tanstack-start": "tanstack-start";
|
|
243
244
|
next: "next";
|
|
244
245
|
nuxt: "nuxt";
|
|
245
|
-
"native-
|
|
246
|
+
"native-bare": "native-bare";
|
|
247
|
+
"native-uniwind": "native-uniwind";
|
|
246
248
|
"native-unistyles": "native-unistyles";
|
|
247
249
|
svelte: "svelte";
|
|
248
250
|
solid: "solid";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-
|
|
2
|
+
import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-82W1Q-C5.js";
|
|
3
3
|
|
|
4
4
|
export { builder, createBtsCli, docs, init, router, sponsors };
|
|
@@ -146,7 +146,7 @@ const dependencyVersionMap = {
|
|
|
146
146
|
"nitro-cloudflare-dev": "^0.2.2",
|
|
147
147
|
"@sveltejs/adapter-cloudflare": "^7.2.1",
|
|
148
148
|
"@cloudflare/workers-types": "^4.20250822.0",
|
|
149
|
-
alchemy: "^0.
|
|
149
|
+
alchemy: "^0.77.0",
|
|
150
150
|
dotenv: "^17.2.2",
|
|
151
151
|
tsdown: "^0.15.5",
|
|
152
152
|
zod: "^4.1.11",
|
|
@@ -216,7 +216,8 @@ const FrontendSchema = z.enum([
|
|
|
216
216
|
"tanstack-start",
|
|
217
217
|
"next",
|
|
218
218
|
"nuxt",
|
|
219
|
-
"native-
|
|
219
|
+
"native-bare",
|
|
220
|
+
"native-uniwind",
|
|
220
221
|
"native-unistyles",
|
|
221
222
|
"svelte",
|
|
222
223
|
"solid",
|
|
@@ -337,13 +338,13 @@ function isWebFrontend(value) {
|
|
|
337
338
|
function splitFrontends(values = []) {
|
|
338
339
|
return {
|
|
339
340
|
web: values.filter((f) => isWebFrontend(f)),
|
|
340
|
-
native: values.filter((f) => f === "native-
|
|
341
|
+
native: values.filter((f) => f === "native-bare" || f === "native-uniwind" || f === "native-unistyles")
|
|
341
342
|
};
|
|
342
343
|
}
|
|
343
344
|
function ensureSingleWebAndNative(frontends) {
|
|
344
345
|
const { web, native } = splitFrontends(frontends);
|
|
345
346
|
if (web.length > 1) exitWithError("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid");
|
|
346
|
-
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-
|
|
347
|
+
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
|
|
347
348
|
}
|
|
348
349
|
const FULLSTACK_FRONTENDS$1 = ["next", "tanstack-start"];
|
|
349
350
|
function validateSelfBackendCompatibility(providedFlags, options, config) {
|
|
@@ -352,7 +353,7 @@ function validateSelfBackendCompatibility(providedFlags, options, config) {
|
|
|
352
353
|
if (backend === "self") {
|
|
353
354
|
const { web, native } = splitFrontends(frontends);
|
|
354
355
|
if (!(web.length === 1 && FULLSTACK_FRONTENDS$1.includes(web[0]))) exitWithError("Backend 'self' (fullstack) currently only supports Next.js and TanStack Start frontends. Please use --frontend next or --frontend tanstack-start. Support for Nuxt and SvelteKit will be added in a future update.");
|
|
355
|
-
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-
|
|
356
|
+
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
|
|
356
357
|
}
|
|
357
358
|
const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
|
|
358
359
|
if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) currently only supports Next.js and TanStack Start frontends. Please use --frontend next or --frontend tanstack-start or choose a different backend. Support for Nuxt and SvelteKit will be added in a future update.");
|
|
@@ -622,7 +623,8 @@ async function getAuthChoice(auth, backend, frontend) {
|
|
|
622
623
|
"tanstack-router",
|
|
623
624
|
"tanstack-start",
|
|
624
625
|
"next",
|
|
625
|
-
"native-
|
|
626
|
+
"native-bare",
|
|
627
|
+
"native-uniwind",
|
|
626
628
|
"native-unistyles"
|
|
627
629
|
].includes(f));
|
|
628
630
|
const hasClerkCompatibleFrontends = frontend?.some((f) => [
|
|
@@ -630,7 +632,8 @@ async function getAuthChoice(auth, backend, frontend) {
|
|
|
630
632
|
"tanstack-router",
|
|
631
633
|
"tanstack-start",
|
|
632
634
|
"next",
|
|
633
|
-
"native-
|
|
635
|
+
"native-bare",
|
|
636
|
+
"native-uniwind",
|
|
634
637
|
"native-unistyles"
|
|
635
638
|
].includes(f));
|
|
636
639
|
const options = [];
|
|
@@ -965,16 +968,24 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
|
965
968
|
if (frontendTypes.includes("native")) {
|
|
966
969
|
const nativeFramework = await select({
|
|
967
970
|
message: "Choose native",
|
|
968
|
-
options: [
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
971
|
+
options: [
|
|
972
|
+
{
|
|
973
|
+
value: "native-bare",
|
|
974
|
+
label: "Bare",
|
|
975
|
+
hint: "Bare Expo without styling library"
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
value: "native-uniwind",
|
|
979
|
+
label: "Uniwind",
|
|
980
|
+
hint: "Use Tailwind CSS for React Native"
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
value: "native-unistyles",
|
|
984
|
+
label: "Unistyles",
|
|
985
|
+
hint: "Consistent styling for React Native"
|
|
986
|
+
}
|
|
987
|
+
],
|
|
988
|
+
initialValue: "native-bare"
|
|
978
989
|
});
|
|
979
990
|
if (isCancel(nativeFramework)) return exitCancelled("Operation cancelled");
|
|
980
991
|
result.push(nativeFramework);
|
|
@@ -1733,7 +1744,8 @@ function validateConvexConstraints(config, providedFlags) {
|
|
|
1733
1744
|
"tanstack-router",
|
|
1734
1745
|
"tanstack-start",
|
|
1735
1746
|
"next",
|
|
1736
|
-
"native-
|
|
1747
|
+
"native-bare",
|
|
1748
|
+
"native-uniwind",
|
|
1737
1749
|
"native-unistyles"
|
|
1738
1750
|
];
|
|
1739
1751
|
if (!config.frontend?.some((f) => supportedFrontends.includes(f))) exitWithError("Better-Auth with Convex backend requires a supported frontend (TanStack Router, TanStack Start, Next.js, or Native).");
|
|
@@ -2306,7 +2318,8 @@ function getFrameworksFromFrontend(frontend) {
|
|
|
2306
2318
|
"tanstack-start": "react",
|
|
2307
2319
|
next: "next",
|
|
2308
2320
|
nuxt: "vue",
|
|
2309
|
-
"native-
|
|
2321
|
+
"native-bare": "react",
|
|
2322
|
+
"native-uniwind": "react",
|
|
2310
2323
|
"native-unistyles": "react",
|
|
2311
2324
|
svelte: "svelte",
|
|
2312
2325
|
solid: "solid"
|
|
@@ -2759,7 +2772,8 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2759
2772
|
const hasNuxtWeb = context.frontend.includes("nuxt");
|
|
2760
2773
|
const hasSvelteWeb = context.frontend.includes("svelte");
|
|
2761
2774
|
const hasSolidWeb = context.frontend.includes("solid");
|
|
2762
|
-
const
|
|
2775
|
+
const hasNativeBare = context.frontend.includes("native-bare");
|
|
2776
|
+
const hasNativeUniwind = context.frontend.includes("native-uniwind");
|
|
2763
2777
|
const hasUnistyles = context.frontend.includes("native-unistyles");
|
|
2764
2778
|
const isConvex = context.backend === "convex";
|
|
2765
2779
|
if (hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) {
|
|
@@ -2809,13 +2823,14 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2809
2823
|
}
|
|
2810
2824
|
}
|
|
2811
2825
|
}
|
|
2812
|
-
if (
|
|
2826
|
+
if (hasNativeBare || hasNativeUniwind || hasUnistyles) {
|
|
2813
2827
|
const nativeAppDir = path.join(projectDir, "apps/native");
|
|
2814
2828
|
await fs.ensureDir(nativeAppDir);
|
|
2815
2829
|
const nativeBaseCommonDir = path.join(PKG_ROOT, "templates/frontend/native/base");
|
|
2816
2830
|
if (await fs.pathExists(nativeBaseCommonDir)) await processAndCopyFiles("**/*", nativeBaseCommonDir, nativeAppDir, context);
|
|
2817
2831
|
let nativeFrameworkPath = "";
|
|
2818
|
-
if (
|
|
2832
|
+
if (hasNativeBare) nativeFrameworkPath = "bare";
|
|
2833
|
+
else if (hasNativeUniwind) nativeFrameworkPath = "uniwind";
|
|
2819
2834
|
else if (hasUnistyles) nativeFrameworkPath = "unistyles";
|
|
2820
2835
|
const nativeSpecificDir = path.join(PKG_ROOT, `templates/frontend/native/${nativeFrameworkPath}`);
|
|
2821
2836
|
if (await fs.pathExists(nativeSpecificDir)) await processAndCopyFiles("**/*", nativeSpecificDir, nativeAppDir, context, true);
|
|
@@ -2889,9 +2904,10 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2889
2904
|
const hasNuxtWeb = context.frontend.includes("nuxt");
|
|
2890
2905
|
const hasSvelteWeb = context.frontend.includes("svelte");
|
|
2891
2906
|
const hasSolidWeb = context.frontend.includes("solid");
|
|
2892
|
-
const
|
|
2907
|
+
const hasNativeBare = context.frontend.includes("native-bare");
|
|
2908
|
+
const hasUniwind = context.frontend.includes("native-uniwind");
|
|
2893
2909
|
const hasUnistyles = context.frontend.includes("native-unistyles");
|
|
2894
|
-
const hasNative =
|
|
2910
|
+
const hasNative = hasNativeBare || hasUniwind || hasUnistyles;
|
|
2895
2911
|
const authProvider = context.auth;
|
|
2896
2912
|
if (context.backend === "convex" && authProvider === "clerk") {
|
|
2897
2913
|
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
@@ -2915,11 +2931,10 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2915
2931
|
if (nativeAppDirExists) {
|
|
2916
2932
|
const convexClerkNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/clerk/convex/native/base");
|
|
2917
2933
|
if (await fs.pathExists(convexClerkNativeBaseSrc)) await processAndCopyFiles("**/*", convexClerkNativeBaseSrc, nativeAppDir, context);
|
|
2918
|
-
const hasNativeWind$1 = context.frontend.includes("native-nativewind");
|
|
2919
|
-
const hasUnistyles$1 = context.frontend.includes("native-unistyles");
|
|
2920
2934
|
let nativeFrameworkPath = "";
|
|
2921
|
-
if (
|
|
2922
|
-
else if (
|
|
2935
|
+
if (hasNativeBare) nativeFrameworkPath = "bare";
|
|
2936
|
+
else if (hasUniwind) nativeFrameworkPath = "uniwind";
|
|
2937
|
+
else if (hasUnistyles) nativeFrameworkPath = "unistyles";
|
|
2923
2938
|
if (nativeFrameworkPath) {
|
|
2924
2939
|
const convexClerkNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/clerk/convex/native/${nativeFrameworkPath}`);
|
|
2925
2940
|
if (await fs.pathExists(convexClerkNativeFrameworkSrc)) await processAndCopyFiles("**/*", convexClerkNativeFrameworkSrc, nativeAppDir, context);
|
|
@@ -2952,7 +2967,8 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2952
2967
|
const convexBetterAuthNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/better-auth/convex/native/base");
|
|
2953
2968
|
if (await fs.pathExists(convexBetterAuthNativeBaseSrc)) await processAndCopyFiles("**/*", convexBetterAuthNativeBaseSrc, nativeAppDir, context);
|
|
2954
2969
|
let nativeFrameworkPath = "";
|
|
2955
|
-
if (
|
|
2970
|
+
if (hasNativeBare) nativeFrameworkPath = "bare";
|
|
2971
|
+
else if (hasUniwind) nativeFrameworkPath = "uniwind";
|
|
2956
2972
|
else if (hasUnistyles) nativeFrameworkPath = "unistyles";
|
|
2957
2973
|
if (nativeFrameworkPath) {
|
|
2958
2974
|
const convexBetterAuthNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/better-auth/convex/native/${nativeFrameworkPath}`);
|
|
@@ -3011,7 +3027,8 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
3011
3027
|
const authNativeBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/base`);
|
|
3012
3028
|
if (await fs.pathExists(authNativeBaseSrc)) await processAndCopyFiles("**/*", authNativeBaseSrc, nativeAppDir, context);
|
|
3013
3029
|
let nativeFrameworkAuthPath = "";
|
|
3014
|
-
if (
|
|
3030
|
+
if (hasNativeBare) nativeFrameworkAuthPath = "bare";
|
|
3031
|
+
else if (hasUniwind) nativeFrameworkAuthPath = "uniwind";
|
|
3015
3032
|
else if (hasUnistyles) nativeFrameworkAuthPath = "unistyles";
|
|
3016
3033
|
if (nativeFrameworkAuthPath) {
|
|
3017
3034
|
const authNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/${nativeFrameworkAuthPath}`);
|
|
@@ -3155,11 +3172,13 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3155
3172
|
}
|
|
3156
3173
|
}
|
|
3157
3174
|
if (nativeAppDirExists) {
|
|
3158
|
-
const
|
|
3175
|
+
const hasNativeBare = context.frontend.includes("native-bare");
|
|
3176
|
+
const hasUniwind = context.frontend.includes("native-uniwind");
|
|
3159
3177
|
const hasUnistyles = context.frontend.includes("native-unistyles");
|
|
3160
|
-
if (
|
|
3178
|
+
if (hasNativeBare || hasUniwind || hasUnistyles) {
|
|
3161
3179
|
let nativeFramework = "";
|
|
3162
|
-
if (
|
|
3180
|
+
if (hasNativeBare) nativeFramework = "bare";
|
|
3181
|
+
else if (hasUniwind) nativeFramework = "uniwind";
|
|
3163
3182
|
else if (hasUnistyles) nativeFramework = "unistyles";
|
|
3164
3183
|
const exampleNativeSrc = path.join(exampleBaseDir, `native/${nativeFramework}`);
|
|
3165
3184
|
if (await fs.pathExists(exampleNativeSrc)) await processAndCopyFiles("**/*", exampleNativeSrc, nativeAppDir, context, false);
|
|
@@ -3169,9 +3188,10 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3169
3188
|
}
|
|
3170
3189
|
async function handleExtras(projectDir, context) {
|
|
3171
3190
|
const extrasDir = path.join(PKG_ROOT, "templates/extras");
|
|
3172
|
-
const
|
|
3191
|
+
const hasNativeBare = context.frontend.includes("native-bare");
|
|
3192
|
+
const hasUniwind = context.frontend.includes("native-uniwind");
|
|
3173
3193
|
const hasUnistyles = context.frontend.includes("native-unistyles");
|
|
3174
|
-
const hasNative =
|
|
3194
|
+
const hasNative = hasNativeBare || hasUniwind || hasUnistyles;
|
|
3175
3195
|
if (context.packageManager === "pnpm") {
|
|
3176
3196
|
const pnpmWorkspaceSrc = path.join(extrasDir, "pnpm-workspace.yaml");
|
|
3177
3197
|
const pnpmWorkspaceDest = path.join(projectDir, "pnpm-workspace.yaml");
|
|
@@ -4032,6 +4052,7 @@ async function setupCatalogs(projectDir, options) {
|
|
|
4032
4052
|
const packagePaths = [
|
|
4033
4053
|
"apps/server",
|
|
4034
4054
|
"apps/web",
|
|
4055
|
+
"apps/native",
|
|
4035
4056
|
"apps/fumadocs",
|
|
4036
4057
|
"apps/docs",
|
|
4037
4058
|
"packages/api",
|
|
@@ -4162,7 +4183,7 @@ async function setupExamples(config) {
|
|
|
4162
4183
|
const hasSvelte = frontend.includes("svelte");
|
|
4163
4184
|
const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
|
|
4164
4185
|
const hasNext = frontend.includes("next");
|
|
4165
|
-
const hasReactNative = frontend.includes("native-
|
|
4186
|
+
const hasReactNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
4166
4187
|
if (webClientDirExists) {
|
|
4167
4188
|
const dependencies = ["ai"];
|
|
4168
4189
|
if (hasNuxt) dependencies.push("@ai-sdk/vue");
|
|
@@ -4207,7 +4228,11 @@ function getFrontendType(frontend) {
|
|
|
4207
4228
|
"tanstack-start",
|
|
4208
4229
|
"next"
|
|
4209
4230
|
];
|
|
4210
|
-
const nativeFrontends = [
|
|
4231
|
+
const nativeFrontends = [
|
|
4232
|
+
"native-bare",
|
|
4233
|
+
"native-uniwind",
|
|
4234
|
+
"native-unistyles"
|
|
4235
|
+
];
|
|
4211
4236
|
return {
|
|
4212
4237
|
hasReactWeb: frontend.some((f) => reactBasedFrontends.includes(f)),
|
|
4213
4238
|
hasNuxtWeb: frontend.includes("nuxt"),
|
|
@@ -4282,13 +4307,14 @@ function getQueryDependencies(frontend) {
|
|
|
4282
4307
|
"tanstack-router",
|
|
4283
4308
|
"tanstack-start",
|
|
4284
4309
|
"next",
|
|
4285
|
-
"native-
|
|
4310
|
+
"native-bare",
|
|
4311
|
+
"native-uniwind",
|
|
4286
4312
|
"native-unistyles"
|
|
4287
4313
|
];
|
|
4288
4314
|
const deps = {};
|
|
4289
4315
|
if (frontend.some((f) => reactBasedFrontends.includes(f))) {
|
|
4290
|
-
const hasReactWeb = frontend.some((f) => f !== "native-
|
|
4291
|
-
const hasNative = frontend.includes("native-
|
|
4316
|
+
const hasReactWeb = frontend.some((f) => f !== "native-bare" && f !== "native-uniwind" && f !== "native-unistyles" && reactBasedFrontends.includes(f));
|
|
4317
|
+
const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
4292
4318
|
if (hasReactWeb) deps.web = {
|
|
4293
4319
|
dependencies: ["@tanstack/react-query"],
|
|
4294
4320
|
devDependencies: ["@tanstack/react-query-devtools"]
|
|
@@ -4440,7 +4466,7 @@ async function setupBetterAuthPlugins(projectDir, config) {
|
|
|
4440
4466
|
pluginsToAdd.push("nextCookies()");
|
|
4441
4467
|
importsToAdd.push("import { nextCookies } from \"better-auth/next-js\";");
|
|
4442
4468
|
}
|
|
4443
|
-
if (config.frontend?.includes("native-
|
|
4469
|
+
if (config.frontend?.includes("native-bare") || config.frontend?.includes("native-uniwind") || config.frontend?.includes("native-unistyles")) {
|
|
4444
4470
|
pluginsToAdd.push("expo()");
|
|
4445
4471
|
importsToAdd.push("import { expo } from \"@better-auth/expo\";");
|
|
4446
4472
|
}
|
|
@@ -4497,7 +4523,7 @@ async function setupAuth(config) {
|
|
|
4497
4523
|
if (auth === "better-auth") {
|
|
4498
4524
|
const convexBackendDir = path.join(projectDir, "packages/backend");
|
|
4499
4525
|
const convexBackendDirExists = await fs.pathExists(convexBackendDir);
|
|
4500
|
-
const hasNativeForBA = frontend.includes("native-
|
|
4526
|
+
const hasNativeForBA = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
4501
4527
|
if (convexBackendDirExists) {
|
|
4502
4528
|
await addPackageDependency({
|
|
4503
4529
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
@@ -4530,9 +4556,10 @@ async function setupAuth(config) {
|
|
|
4530
4556
|
projectDir: clientDir
|
|
4531
4557
|
});
|
|
4532
4558
|
}
|
|
4533
|
-
const
|
|
4559
|
+
const hasNativeBare$1 = frontend.includes("native-bare");
|
|
4560
|
+
const hasNativeUniwind$1 = frontend.includes("native-uniwind");
|
|
4534
4561
|
const hasUnistyles$1 = frontend.includes("native-unistyles");
|
|
4535
|
-
if (nativeDirExists && (
|
|
4562
|
+
if (nativeDirExists && (hasNativeBare$1 || hasNativeUniwind$1 || hasUnistyles$1)) await addPackageDependency({
|
|
4536
4563
|
dependencies: [
|
|
4537
4564
|
"better-auth",
|
|
4538
4565
|
"@better-auth/expo",
|
|
@@ -4545,9 +4572,10 @@ async function setupAuth(config) {
|
|
|
4545
4572
|
projectDir: nativeDir
|
|
4546
4573
|
});
|
|
4547
4574
|
}
|
|
4548
|
-
const
|
|
4575
|
+
const hasNativeBare = frontend.includes("native-bare");
|
|
4576
|
+
const hasNativeUniwind = frontend.includes("native-uniwind");
|
|
4549
4577
|
const hasUnistyles = frontend.includes("native-unistyles");
|
|
4550
|
-
if (auth === "clerk" && nativeDirExists && (
|
|
4578
|
+
if (auth === "clerk" && nativeDirExists && (hasNativeBare || hasNativeUniwind || hasUnistyles)) await addPackageDependency({
|
|
4551
4579
|
dependencies: ["@clerk/clerk-expo"],
|
|
4552
4580
|
projectDir: nativeDir
|
|
4553
4581
|
});
|
|
@@ -4573,7 +4601,7 @@ async function setupAuth(config) {
|
|
|
4573
4601
|
projectDir: clientDir
|
|
4574
4602
|
});
|
|
4575
4603
|
}
|
|
4576
|
-
if ((frontend.includes("native-
|
|
4604
|
+
if ((frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) && nativeDirExists) {
|
|
4577
4605
|
if (auth === "better-auth") {
|
|
4578
4606
|
await addPackageDependency({
|
|
4579
4607
|
dependencies: ["better-auth", "@better-auth/expo"],
|
|
@@ -4740,7 +4768,7 @@ async function setupEnvironmentVariables(config) {
|
|
|
4740
4768
|
await addEnvVariablesToFile(path.join(clientDir, ".env"), clientVars);
|
|
4741
4769
|
}
|
|
4742
4770
|
}
|
|
4743
|
-
if (frontend.includes("native-
|
|
4771
|
+
if (frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) {
|
|
4744
4772
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4745
4773
|
if (await fs.pathExists(nativeDir)) {
|
|
4746
4774
|
let envVarName = "EXPO_PUBLIC_SERVER_URL";
|
|
@@ -4773,7 +4801,7 @@ async function setupEnvironmentVariables(config) {
|
|
|
4773
4801
|
const convexBackendDir = path.join(projectDir, "packages/backend");
|
|
4774
4802
|
if (await fs.pathExists(convexBackendDir)) {
|
|
4775
4803
|
const envLocalPath = path.join(convexBackendDir, ".env.local");
|
|
4776
|
-
const hasNative = frontend.includes("native-
|
|
4804
|
+
const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
4777
4805
|
const hasWeb = hasWebFrontend$1;
|
|
4778
4806
|
if (!await fs.pathExists(envLocalPath) || !(await fs.readFile(envLocalPath, "utf8")).includes("npx convex env set")) {
|
|
4779
4807
|
const convexCommands = `# Set Convex environment variables
|
|
@@ -6082,7 +6110,7 @@ function generateReadmeContent(options) {
|
|
|
6082
6110
|
const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc", webDeploy, serverDeploy } = options;
|
|
6083
6111
|
const isConvex = backend === "convex";
|
|
6084
6112
|
const hasReactRouter = frontend.includes("react-router");
|
|
6085
|
-
const hasNative = frontend.includes("native-
|
|
6113
|
+
const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
6086
6114
|
const hasSvelte = frontend.includes("svelte");
|
|
6087
6115
|
const packageManagerRunCmd = `${packageManager} run`;
|
|
6088
6116
|
let webPort = "3001";
|
|
@@ -6208,7 +6236,7 @@ function generateProjectStructure(projectName, frontend, backend, addons, isConv
|
|
|
6208
6236
|
else structure.push(`│ ├── web/ # Frontend application (${frontendType})`);
|
|
6209
6237
|
}
|
|
6210
6238
|
}
|
|
6211
|
-
if (frontend.includes("native-
|
|
6239
|
+
if (frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) if (isBackendSelf) structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
|
|
6212
6240
|
else structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
|
|
6213
6241
|
if (addons.includes("starlight")) if (isBackendSelf) structure.push("│ ├── docs/ # Documentation site (Astro Starlight)");
|
|
6214
6242
|
else structure.push("│ ├── docs/ # Documentation site (Astro Starlight)");
|
|
@@ -6237,7 +6265,7 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
6237
6265
|
const isBackendNone = backend === "none";
|
|
6238
6266
|
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
6239
6267
|
const hasReactRouter = frontend.includes("react-router");
|
|
6240
|
-
const hasNative = frontend.includes("native-
|
|
6268
|
+
const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
6241
6269
|
const hasNext = frontend.includes("next");
|
|
6242
6270
|
const hasTanstackStart = frontend.includes("tanstack-start");
|
|
6243
6271
|
const hasSvelte = frontend.includes("svelte");
|
|
@@ -6516,7 +6544,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6516
6544
|
const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy, backend) : "";
|
|
6517
6545
|
const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
|
|
6518
6546
|
const lintingInstructions = hasHuskyOrBiome ? getLintingInstructions(runCmd) : "";
|
|
6519
|
-
const nativeInstructions = frontend?.includes("native-
|
|
6547
|
+
const nativeInstructions = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles") ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
|
|
6520
6548
|
const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
|
|
6521
6549
|
const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
|
|
6522
6550
|
const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
|
|
@@ -6532,7 +6560,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6532
6560
|
"svelte",
|
|
6533
6561
|
"solid"
|
|
6534
6562
|
].includes(f));
|
|
6535
|
-
const hasNative = frontend?.includes("native-
|
|
6563
|
+
const hasNative = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles");
|
|
6536
6564
|
const bunWebNativeWarning = packageManager === "bun" && hasNative && hasWeb ? getBunWebNativeWarning() : "";
|
|
6537
6565
|
const noOrmWarning = !isConvex && database !== "none" && orm === "none" ? getNoOrmWarning() : "";
|
|
6538
6566
|
const hasReactRouter = frontend?.includes("react-router");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createClient, type GenericCtx } from "@convex-dev/better-auth";
|
|
2
|
-
{{#if (or (includes frontend "native-
|
|
2
|
+
{{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
3
3
|
import { convex } from "@convex-dev/better-auth/plugins";
|
|
4
4
|
import { expo } from "@better-auth/expo";
|
|
5
5
|
{{else}}
|
|
@@ -17,7 +17,7 @@ import { v } from "convex/values";
|
|
|
17
17
|
{{#if (or (includes frontend "tanstack-start") (includes frontend "next") (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
18
18
|
const siteUrl = process.env.SITE_URL!;
|
|
19
19
|
{{/if}}
|
|
20
|
-
{{#if (or (includes frontend "native-
|
|
20
|
+
{{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
21
21
|
const nativeAppUrl = process.env.NATIVE_APP_URL || "mybettertapp://";
|
|
22
22
|
{{/if}}
|
|
23
23
|
|
|
@@ -31,10 +31,10 @@ function createAuth(
|
|
|
31
31
|
logger: {
|
|
32
32
|
disabled: optionsOnly,
|
|
33
33
|
},
|
|
34
|
-
{{#if (and (or (includes frontend "native-
|
|
34
|
+
{{#if (and (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles")) (or (includes frontend "tanstack-start") (includes frontend "next")))}}
|
|
35
35
|
baseURL: siteUrl,
|
|
36
36
|
trustedOrigins: [siteUrl, nativeAppUrl],
|
|
37
|
-
{{else if (or (includes frontend "native-
|
|
37
|
+
{{else if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
38
38
|
trustedOrigins: [nativeAppUrl],
|
|
39
39
|
{{else if (or (includes frontend "tanstack-start") (includes frontend "next"))}}
|
|
40
40
|
baseURL: siteUrl,
|
|
@@ -48,7 +48,7 @@ function createAuth(
|
|
|
48
48
|
requireEmailVerification: false,
|
|
49
49
|
},
|
|
50
50
|
plugins: [
|
|
51
|
-
{{#if (or (includes frontend "native-
|
|
51
|
+
{{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
52
52
|
expo(),
|
|
53
53
|
{{/if}}
|
|
54
54
|
{{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
@@ -3,7 +3,7 @@ import { authComponent, createAuth } from "./auth";
|
|
|
3
3
|
|
|
4
4
|
const http = httpRouter();
|
|
5
5
|
|
|
6
|
-
{{#if (or (includes frontend "tanstack-start") (includes frontend "next") (includes frontend "native-
|
|
6
|
+
{{#if (or (includes frontend "tanstack-start") (includes frontend "next") (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
7
7
|
authComponent.registerRoutes(http, createAuth);
|
|
8
8
|
{{else}}
|
|
9
9
|
authComponent.registerRoutes(http, createAuth, { cors: true });
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { authClient } from "@/lib/auth-client";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
ActivityIndicator,
|
|
5
|
+
Text,
|
|
6
|
+
TextInput,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
View,
|
|
9
|
+
StyleSheet,
|
|
10
|
+
} from "react-native";
|
|
11
|
+
import { useColorScheme } from "@/lib/use-color-scheme";
|
|
12
|
+
import { NAV_THEME } from "@/lib/constants";
|
|
13
|
+
|
|
14
|
+
function SignIn() {
|
|
15
|
+
const { colorScheme } = useColorScheme();
|
|
16
|
+
const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
|
|
17
|
+
const [email, setEmail] = useState("");
|
|
18
|
+
const [password, setPassword] = useState("");
|
|
19
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
20
|
+
const [error, setError] = useState<string | null>(null);
|
|
21
|
+
|
|
22
|
+
async function handleLogin() {
|
|
23
|
+
setIsLoading(true);
|
|
24
|
+
setError(null);
|
|
25
|
+
|
|
26
|
+
await authClient.signIn.email(
|
|
27
|
+
{
|
|
28
|
+
email,
|
|
29
|
+
password,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
onError(error) {
|
|
33
|
+
setError(error.error?.message || "Failed to sign in");
|
|
34
|
+
setIsLoading(false);
|
|
35
|
+
},
|
|
36
|
+
onSuccess() {
|
|
37
|
+
setEmail("");
|
|
38
|
+
setPassword("");
|
|
39
|
+
},
|
|
40
|
+
onFinished() {
|
|
41
|
+
setIsLoading(false);
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>
|
|
49
|
+
<Text style={[styles.title, { color: theme.text }]}>Sign In</Text>
|
|
50
|
+
|
|
51
|
+
{error ? (
|
|
52
|
+
<View style={[styles.errorContainer, { backgroundColor: theme.notification + "20" }]}>
|
|
53
|
+
<Text style={[styles.errorText, { color: theme.notification }]}>{error}</Text>
|
|
54
|
+
</View>
|
|
55
|
+
) : null}
|
|
56
|
+
|
|
57
|
+
<TextInput
|
|
58
|
+
style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
|
|
59
|
+
placeholder="Email"
|
|
60
|
+
placeholderTextColor={theme.text}
|
|
61
|
+
value={email}
|
|
62
|
+
onChangeText={setEmail}
|
|
63
|
+
keyboardType="email-address"
|
|
64
|
+
autoCapitalize="none"
|
|
65
|
+
/>
|
|
66
|
+
|
|
67
|
+
<TextInput
|
|
68
|
+
style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
|
|
69
|
+
placeholder="Password"
|
|
70
|
+
placeholderTextColor={theme.text}
|
|
71
|
+
value={password}
|
|
72
|
+
onChangeText={setPassword}
|
|
73
|
+
secureTextEntry
|
|
74
|
+
/>
|
|
75
|
+
|
|
76
|
+
<TouchableOpacity
|
|
77
|
+
onPress={handleLogin}
|
|
78
|
+
disabled={isLoading}
|
|
79
|
+
style={[styles.button, { backgroundColor: theme.primary, opacity: isLoading ? 0.5 : 1 }]}
|
|
80
|
+
>
|
|
81
|
+
{isLoading ? (
|
|
82
|
+
<ActivityIndicator size="small" color="#ffffff" />
|
|
83
|
+
) : (
|
|
84
|
+
<Text style={styles.buttonText}>Sign In</Text>
|
|
85
|
+
)}
|
|
86
|
+
</TouchableOpacity>
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const styles = StyleSheet.create({
|
|
92
|
+
card: {
|
|
93
|
+
marginTop: 16,
|
|
94
|
+
padding: 16,
|
|
95
|
+
borderWidth: 1,
|
|
96
|
+
},
|
|
97
|
+
title: {
|
|
98
|
+
fontSize: 18,
|
|
99
|
+
fontWeight: "bold",
|
|
100
|
+
marginBottom: 12,
|
|
101
|
+
},
|
|
102
|
+
errorContainer: {
|
|
103
|
+
marginBottom: 12,
|
|
104
|
+
padding: 8,
|
|
105
|
+
},
|
|
106
|
+
errorText: {
|
|
107
|
+
fontSize: 14,
|
|
108
|
+
},
|
|
109
|
+
input: {
|
|
110
|
+
borderWidth: 1,
|
|
111
|
+
padding: 12,
|
|
112
|
+
fontSize: 16,
|
|
113
|
+
marginBottom: 12,
|
|
114
|
+
},
|
|
115
|
+
button: {
|
|
116
|
+
padding: 12,
|
|
117
|
+
alignItems: "center",
|
|
118
|
+
justifyContent: "center",
|
|
119
|
+
},
|
|
120
|
+
buttonText: {
|
|
121
|
+
color: "#ffffff",
|
|
122
|
+
fontSize: 16,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export { SignIn };
|
|
127
|
+
|