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:
@@ -125,7 +125,8 @@ export async function setupApi(config: ProjectConfig): Promise<void> {
|
||||
"tanstack-router",
|
||||
"tanstack-start",
|
||||
"next",
|
||||
"native",
|
||||
"native-nativewind",
|
||||
"native-unistyles",
|
||||
];
|
||||
const needsSolidQuery = frontend.includes("solid");
|
||||
const needsReactQuery = frontend.some((f) => reactBasedFrontends.includes(f));
|
||||
@@ -137,9 +138,14 @@ export async function setupApi(config: ProjectConfig): Promise<void> {
|
||||
];
|
||||
|
||||
const hasReactWeb = frontend.some(
|
||||
(f) => f !== "native" && reactBasedFrontends.includes(f),
|
||||
(f) =>
|
||||
f !== "native-nativewind" &&
|
||||
f !== "native-unistyles" &&
|
||||
reactBasedFrontends.includes(f),
|
||||
);
|
||||
const hasNative = frontend.includes("native");
|
||||
const hasNative =
|
||||
frontend.includes("native-nativewind") ||
|
||||
frontend.includes("native-unistyles");
|
||||
|
||||
if (hasReactWeb && webDirExists) {
|
||||
const webPkgJsonPath = path.join(webDir, "package.json");
|
||||
|
||||
@@ -45,7 +45,11 @@ export async function setupAuth(config: ProjectConfig): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
if (frontend.includes("native") && nativeDirExists) {
|
||||
if (
|
||||
(frontend.includes("native-nativewind") ||
|
||||
frontend.includes("native-unistyles")) &&
|
||||
nativeDirExists
|
||||
) {
|
||||
await addPackageDependency({
|
||||
dependencies: ["better-auth", "@better-auth/expo"],
|
||||
projectDir: nativeDir,
|
||||
|
||||
@@ -39,7 +39,9 @@ function generateReadmeContent(options: ProjectConfig): string {
|
||||
const isConvex = backend === "convex";
|
||||
const hasReactRouter = frontend.includes("react-router");
|
||||
const hasTanstackRouter = frontend.includes("tanstack-router");
|
||||
const hasNative = frontend.includes("native");
|
||||
const hasNative =
|
||||
frontend.includes("native-nativewind") ||
|
||||
frontend.includes("native-unistyles");
|
||||
const hasNext = frontend.includes("next");
|
||||
const hasTanstackStart = frontend.includes("tanstack-start");
|
||||
const hasSvelte = frontend.includes("svelte");
|
||||
@@ -78,7 +80,16 @@ This project was created with [Better-T-Stack](https://github.com/AmanVarshney01
|
||||
|
||||
## Features
|
||||
|
||||
${generateFeaturesList(database, auth, addons, orm, runtime, frontend, backend, api)}
|
||||
${generateFeaturesList(
|
||||
database,
|
||||
auth,
|
||||
addons,
|
||||
orm,
|
||||
runtime,
|
||||
frontend,
|
||||
backend,
|
||||
api,
|
||||
)}
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -207,7 +218,9 @@ function generateFeaturesList(
|
||||
const isConvex = backend === "convex";
|
||||
const hasTanstackRouter = frontend.includes("tanstack-router");
|
||||
const hasReactRouter = frontend.includes("react-router");
|
||||
const hasNative = frontend.includes("native");
|
||||
const hasNative =
|
||||
frontend.includes("native-nativewind") ||
|
||||
frontend.includes("native-unistyles");
|
||||
const hasNext = frontend.includes("next");
|
||||
const hasTanstackStart = frontend.includes("tanstack-start");
|
||||
const hasSvelte = frontend.includes("svelte");
|
||||
|
||||
@@ -118,7 +118,10 @@ export async function setupEnvironmentVariables(
|
||||
}
|
||||
}
|
||||
|
||||
if (frontend.includes("native")) {
|
||||
if (
|
||||
frontend.includes("native-nativewind") ||
|
||||
frontend.includes("native-unistyles")
|
||||
) {
|
||||
const nativeDir = path.join(projectDir, "apps/native");
|
||||
if (await fs.pathExists(nativeDir)) {
|
||||
let envVarName = "EXPO_PUBLIC_SERVER_URL";
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { consola } from "consola";
|
||||
import pc from "picocolors";
|
||||
import type {
|
||||
ProjectBackend,
|
||||
ProjectDatabase,
|
||||
ProjectOrm,
|
||||
ProjectRuntime,
|
||||
} from "../types";
|
||||
import type { ProjectDatabase, ProjectOrm, ProjectRuntime } from "../types";
|
||||
import { getPackageExecutionCommand } from "../utils/get-package-execution-command";
|
||||
|
||||
import type { ProjectConfig } from "../types";
|
||||
@@ -43,9 +38,11 @@ export function displayPostInstallInstructions(
|
||||
const lintingInstructions = hasHuskyOrBiome
|
||||
? getLintingInstructions(runCmd)
|
||||
: "";
|
||||
const nativeInstructions = frontend?.includes("native")
|
||||
? getNativeInstructions(isConvex)
|
||||
: "";
|
||||
const nativeInstructions =
|
||||
frontend?.includes("native-nativewind") ||
|
||||
frontend?.includes("native-unistyles")
|
||||
? getNativeInstructions(isConvex)
|
||||
: "";
|
||||
const pwaInstructions =
|
||||
addons?.includes("pwa") &&
|
||||
(frontend?.includes("react-router") ||
|
||||
@@ -67,7 +64,9 @@ export function displayPostInstallInstructions(
|
||||
"solid",
|
||||
].includes(f),
|
||||
);
|
||||
const hasNative = frontend?.includes("native");
|
||||
const hasNative =
|
||||
frontend?.includes("native-nativewind") ||
|
||||
frontend?.includes("native-unistyles");
|
||||
|
||||
const bunWebNativeWarning =
|
||||
packageManager === "bun" && hasNative && hasWeb
|
||||
@@ -90,7 +89,9 @@ export function displayPostInstallInstructions(
|
||||
}
|
||||
|
||||
if (isConvex) {
|
||||
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup ${pc.dim("(this will guide you through Convex project setup)")}\n`;
|
||||
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup ${pc.dim(
|
||||
"(this will guide you through Convex project setup)",
|
||||
)}\n`;
|
||||
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n\n`;
|
||||
} else {
|
||||
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n\n`;
|
||||
@@ -101,7 +102,9 @@ export function displayPostInstallInstructions(
|
||||
if (hasWeb) {
|
||||
output += `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n`;
|
||||
} else if (!hasNative && !addons?.includes("starlight")) {
|
||||
output += `${pc.yellow("NOTE:")} You are creating a backend-only app (no frontend selected)\n`;
|
||||
output += `${pc.yellow(
|
||||
"NOTE:",
|
||||
)} You are creating a backend-only app (no frontend selected)\n`;
|
||||
}
|
||||
|
||||
if (!isConvex) {
|
||||
@@ -122,8 +125,12 @@ export function displayPostInstallInstructions(
|
||||
if (noOrmWarning) output += `\n${noOrmWarning.trim()}\n`;
|
||||
if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
|
||||
|
||||
output += `\n${pc.bold("Update all dependencies:\n")}${pc.cyan(tazeCommand)}\n\n`;
|
||||
output += `${pc.bold("Like Better-T Stack?")} Please consider giving us a star on GitHub:\n`;
|
||||
output += `\n${pc.bold("Update all dependencies:\n")}${pc.cyan(
|
||||
tazeCommand,
|
||||
)}\n\n`;
|
||||
output += `${pc.bold(
|
||||
"Like Better-T Stack?",
|
||||
)} Please consider giving us a star on GitHub:\n`;
|
||||
output += pc.cyan("https://github.com/AmanVarshney01/create-better-t-stack");
|
||||
|
||||
consola.box(output);
|
||||
@@ -183,7 +190,9 @@ function getDatabaseInstructions(
|
||||
instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
|
||||
if (database === "sqlite") {
|
||||
instructions.push(
|
||||
`${pc.cyan("•")} Start local DB (if needed): ${`cd apps/server && ${runCmd} db:local`}`,
|
||||
`${pc.cyan(
|
||||
"•",
|
||||
)} Start local DB (if needed): ${`cd apps/server && ${runCmd} db:local`}`,
|
||||
);
|
||||
}
|
||||
} else if (orm === "none") {
|
||||
|
||||
@@ -70,7 +70,9 @@ export async function setupFrontendTemplates(
|
||||
const hasNuxtWeb = context.frontend.includes("nuxt");
|
||||
const hasSvelteWeb = context.frontend.includes("svelte");
|
||||
const hasSolidWeb = context.frontend.includes("solid");
|
||||
const hasNative = context.frontend.includes("native");
|
||||
const hasNativeWind = context.frontend.includes("native-nativewind");
|
||||
const hasUnistyles = context.frontend.includes("native-unistyles");
|
||||
const hasNative = hasNativeWind || hasUnistyles;
|
||||
const isConvex = context.backend === "convex";
|
||||
|
||||
if (hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) {
|
||||
@@ -181,16 +183,45 @@ export async function setupFrontendTemplates(
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNative) {
|
||||
if (hasNativeWind || hasUnistyles) {
|
||||
const nativeAppDir = path.join(projectDir, "apps/native");
|
||||
await fs.ensureDir(nativeAppDir);
|
||||
|
||||
const nativeBaseDir = path.join(PKG_ROOT, "templates/frontend/native");
|
||||
if (await fs.pathExists(nativeBaseDir)) {
|
||||
await processAndCopyFiles("**/*", nativeBaseDir, nativeAppDir, context);
|
||||
const nativeBaseCommonDir = path.join(
|
||||
PKG_ROOT,
|
||||
"templates/frontend/native/native-base",
|
||||
);
|
||||
if (await fs.pathExists(nativeBaseCommonDir)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
nativeBaseCommonDir,
|
||||
nativeAppDir,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
}
|
||||
|
||||
let nativeFrameworkPath = "";
|
||||
if (hasNativeWind) {
|
||||
nativeFrameworkPath = "nativewind";
|
||||
} else if (hasUnistyles) {
|
||||
nativeFrameworkPath = "unistyles";
|
||||
}
|
||||
|
||||
const nativeSpecificDir = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/frontend/native/${nativeFrameworkPath}`,
|
||||
);
|
||||
if (await fs.pathExists(nativeSpecificDir)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
nativeSpecificDir,
|
||||
nativeAppDir,
|
||||
context,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isConvex && (context.api === "trpc" || context.api === "orpc")) {
|
||||
const apiNativeSrcDir = path.join(
|
||||
PKG_ROOT,
|
||||
@@ -203,7 +234,6 @@ export async function setupFrontendTemplates(
|
||||
nativeAppDir,
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,7 +375,9 @@ export async function setupAuthTemplate(
|
||||
const hasNuxtWeb = context.frontend.includes("nuxt");
|
||||
const hasSvelteWeb = context.frontend.includes("svelte");
|
||||
const hasSolidWeb = context.frontend.includes("solid");
|
||||
const hasNative = context.frontend.includes("native");
|
||||
const hasNativeWind = context.frontend.includes("native-nativewind");
|
||||
const hasUnistyles = context.frontend.includes("native-unistyles");
|
||||
const hasNative = hasNativeWind || hasUnistyles;
|
||||
|
||||
if (serverAppDirExists) {
|
||||
const authServerBaseSrc = path.join(PKG_ROOT, "templates/auth/server/base");
|
||||
@@ -475,10 +507,39 @@ export async function setupAuthTemplate(
|
||||
}
|
||||
|
||||
if (hasNative && nativeAppDirExists) {
|
||||
const authNativeSrc = path.join(PKG_ROOT, "templates/auth/native");
|
||||
if (await fs.pathExists(authNativeSrc)) {
|
||||
await processAndCopyFiles("**/*", authNativeSrc, nativeAppDir, context);
|
||||
} else {
|
||||
const authNativeBaseSrc = path.join(
|
||||
PKG_ROOT,
|
||||
"templates/auth/native/native-base",
|
||||
);
|
||||
if (await fs.pathExists(authNativeBaseSrc)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
authNativeBaseSrc,
|
||||
nativeAppDir,
|
||||
context,
|
||||
);
|
||||
}
|
||||
|
||||
let nativeFrameworkAuthPath = "";
|
||||
if (hasNativeWind) {
|
||||
nativeFrameworkAuthPath = "nativewind";
|
||||
} else if (hasUnistyles) {
|
||||
nativeFrameworkAuthPath = "unistyles";
|
||||
}
|
||||
|
||||
if (nativeFrameworkAuthPath) {
|
||||
const authNativeFrameworkSrc = path.join(
|
||||
PKG_ROOT,
|
||||
`templates/auth/native/${nativeFrameworkAuthPath}`,
|
||||
);
|
||||
if (await fs.pathExists(authNativeFrameworkSrc)) {
|
||||
await processAndCopyFiles(
|
||||
"**/*",
|
||||
authNativeFrameworkSrc,
|
||||
nativeAppDir,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,6 +756,9 @@ export async function handleExtras(
|
||||
context: ProjectConfig,
|
||||
): Promise<void> {
|
||||
const extrasDir = path.join(PKG_ROOT, "templates/extras");
|
||||
const hasNativeWind = context.frontend.includes("native-nativewind");
|
||||
const hasUnistyles = context.frontend.includes("native-unistyles");
|
||||
const hasNative = hasNativeWind || hasUnistyles;
|
||||
|
||||
if (context.packageManager === "pnpm") {
|
||||
const pnpmWorkspaceSrc = path.join(extrasDir, "pnpm-workspace.yaml");
|
||||
@@ -706,7 +770,7 @@ export async function handleExtras(
|
||||
|
||||
if (
|
||||
context.packageManager === "pnpm" &&
|
||||
(context.frontend.includes("native") || context.frontend.includes("nuxt"))
|
||||
(hasNative || context.frontend.includes("nuxt"))
|
||||
) {
|
||||
const npmrcTemplateSrc = path.join(extrasDir, "_npmrc.hbs");
|
||||
const npmrcDest = path.join(projectDir, ".npmrc");
|
||||
|
||||
@@ -84,7 +84,8 @@ async function main() {
|
||||
"tanstack-start",
|
||||
"next",
|
||||
"nuxt",
|
||||
"native",
|
||||
"native-nativewind",
|
||||
"native-unistyles",
|
||||
"svelte",
|
||||
"solid",
|
||||
"none",
|
||||
@@ -303,6 +304,9 @@ async function main() {
|
||||
config.runtime = "none";
|
||||
config.dbSetup = "none";
|
||||
config.examples = ["todo"];
|
||||
log.info(
|
||||
"Due to '--backend convex' flag, the following options have been automatically set: auth=false, database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo",
|
||||
);
|
||||
} else if (config.backend === "none") {
|
||||
config.auth = false;
|
||||
config.database = "none";
|
||||
@@ -311,10 +315,24 @@ async function main() {
|
||||
config.runtime = "none";
|
||||
config.dbSetup = "none";
|
||||
config.examples = [];
|
||||
log.info(
|
||||
"Due to '--backend none', the following options have been automatically set: --auth=false, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none",
|
||||
);
|
||||
} else if (config.database === "none") {
|
||||
config.orm = "none";
|
||||
log.info(
|
||||
"Due to '--database none', '--orm' has been automatically set to 'none'.",
|
||||
);
|
||||
|
||||
config.auth = false;
|
||||
log.info(
|
||||
"Due to '--database none', '--auth' has been automatically set to 'false'.",
|
||||
);
|
||||
|
||||
config.dbSetup = "none";
|
||||
log.info(
|
||||
"Due to '--database none', '--db-setup' has been automatically set to 'none'.",
|
||||
);
|
||||
}
|
||||
|
||||
log.info(
|
||||
@@ -380,13 +398,16 @@ function processAndValidateFlags(
|
||||
if (options.api) {
|
||||
config.api = options.api as ProjectApi;
|
||||
if (options.api === "none") {
|
||||
if (options.backend && options.backend !== "convex") {
|
||||
if (
|
||||
options.backend &&
|
||||
options.backend !== "convex" &&
|
||||
options.backend !== "none"
|
||||
) {
|
||||
consola.fatal(
|
||||
`'--api none' is only supported with '--backend convex'. Please choose a different API setting or use '--backend convex'.`,
|
||||
`'--api none' is only supported with '--backend convex' or '--backend none'. Please choose a different API setting or use '--backend convex' or '--backend none'.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.backend = "convex";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,12 +489,22 @@ function processAndValidateFlags(
|
||||
f === "svelte" ||
|
||||
f === "solid",
|
||||
);
|
||||
const nativeFrontends = validOptions.filter(
|
||||
(f) => f === "native-nativewind" || f === "native-unistyles",
|
||||
);
|
||||
|
||||
if (webFrontends.length > 1) {
|
||||
consola.fatal(
|
||||
"Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (nativeFrontends.length > 1) {
|
||||
consola.fatal(
|
||||
"Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
config.frontend = validOptions;
|
||||
}
|
||||
}
|
||||
@@ -595,6 +626,9 @@ function processAndValidateFlags(
|
||||
process.exit(1);
|
||||
}
|
||||
config.examples = [];
|
||||
log.info(
|
||||
"Due to '--backend none', the following options have been automatically set: --auth=false, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none",
|
||||
);
|
||||
} else {
|
||||
const effectiveDatabase =
|
||||
config.database ?? (options.yes ? DEFAULT_CONFIG.database : undefined);
|
||||
@@ -621,6 +655,9 @@ function processAndValidateFlags(
|
||||
process.exit(1);
|
||||
}
|
||||
config.orm = "none";
|
||||
log.info(
|
||||
"Due to '--database none', '--orm' has been automatically set to 'none'.",
|
||||
);
|
||||
|
||||
if (providedFlags.has("auth") && options.auth === true) {
|
||||
consola.fatal(
|
||||
@@ -629,6 +666,9 @@ function processAndValidateFlags(
|
||||
process.exit(1);
|
||||
}
|
||||
config.auth = false;
|
||||
log.info(
|
||||
"Due to '--database none', '--auth' has been automatically set to 'false'.",
|
||||
);
|
||||
|
||||
if (providedFlags.has("dbSetup") && options.dbSetup !== "none") {
|
||||
consola.fatal(
|
||||
@@ -637,6 +677,9 @@ function processAndValidateFlags(
|
||||
process.exit(1);
|
||||
}
|
||||
config.dbSetup = "none";
|
||||
log.info(
|
||||
"Due to '--database none', '--db-setup' has been automatically set to 'none'.",
|
||||
);
|
||||
}
|
||||
|
||||
if (config.orm === "mongoose" && !providedFlags.has("database")) {
|
||||
@@ -753,6 +796,9 @@ function processAndValidateFlags(
|
||||
) {
|
||||
if (config.api !== "none") {
|
||||
config.api = "orpc";
|
||||
log.info(
|
||||
`Due to frontend selection, API has been set to 'orpc'. tRPC is not compatible with Nuxt, Svelte, or Solid Framework`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -813,7 +859,8 @@ function processAndValidateFlags(
|
||||
const onlyNativeFrontend =
|
||||
effectiveFrontend &&
|
||||
effectiveFrontend.length === 1 &&
|
||||
effectiveFrontend[0] === "native";
|
||||
(effectiveFrontend[0] === "native-nativewind" ||
|
||||
effectiveFrontend[0] === "native-unistyles");
|
||||
|
||||
if (
|
||||
onlyNativeFrontend &&
|
||||
@@ -822,7 +869,7 @@ function processAndValidateFlags(
|
||||
!config.examples.includes("none")
|
||||
) {
|
||||
consola.fatal(
|
||||
"Examples are not supported when only the 'native' frontend is selected.",
|
||||
"Examples are not supported when only a native frontend (NativeWind or Unistyles) is selected.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ export async function getBackendFrameworkChoice(
|
||||
});
|
||||
}
|
||||
|
||||
// Add "None" option
|
||||
backendOptions.push({
|
||||
value: "none" as const,
|
||||
label: "None",
|
||||
|
||||
@@ -27,7 +27,10 @@ export async function getExamplesChoice(
|
||||
if (database === "none") return [];
|
||||
|
||||
const onlyNative =
|
||||
frontends && frontends.length === 1 && frontends[0] === "native";
|
||||
frontends &&
|
||||
frontends.length === 1 &&
|
||||
(frontends[0] === "native-nativewind" ||
|
||||
frontends[0] === "native-unistyles");
|
||||
if (onlyNative) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -95,7 +95,28 @@ export async function getFrontendChoice(
|
||||
}
|
||||
|
||||
if (frontendTypes.includes("native")) {
|
||||
result.push("native");
|
||||
const nativeFramework = await select<ProjectFrontend>({
|
||||
message: "Choose native framework",
|
||||
options: [
|
||||
{
|
||||
value: "native-nativewind" as const,
|
||||
label: "NativeWind",
|
||||
hint: "Use Tailwind CSS for React Native",
|
||||
},
|
||||
{
|
||||
value: "native-unistyles" as const,
|
||||
label: "Unistyles",
|
||||
hint: "Consistent styling for React Native",
|
||||
},
|
||||
],
|
||||
initialValue: "native-nativewind",
|
||||
});
|
||||
|
||||
if (isCancel(nativeFramework)) {
|
||||
cancel(pc.red("Operation cancelled"));
|
||||
process.exit(0);
|
||||
}
|
||||
result.push(nativeFramework);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -29,7 +29,8 @@ export type ProjectFrontend =
|
||||
| "tanstack-start"
|
||||
| "next"
|
||||
| "nuxt"
|
||||
| "native"
|
||||
| "native-nativewind"
|
||||
| "native-unistyles"
|
||||
| "svelte"
|
||||
| "solid"
|
||||
| "none";
|
||||
|
||||
Reference in New Issue
Block a user