feat(cli): upgrade to expo 54 (#574)
@@ -851,7 +851,7 @@ export async function handleExtras(projectDir: string, context: ProjectConfig) {
|
|||||||
const pnpmWorkspaceSrc = path.join(extrasDir, "pnpm-workspace.yaml");
|
const pnpmWorkspaceSrc = path.join(extrasDir, "pnpm-workspace.yaml");
|
||||||
const pnpmWorkspaceDest = path.join(projectDir, "pnpm-workspace.yaml");
|
const pnpmWorkspaceDest = path.join(projectDir, "pnpm-workspace.yaml");
|
||||||
if (await fs.pathExists(pnpmWorkspaceSrc)) {
|
if (await fs.pathExists(pnpmWorkspaceSrc)) {
|
||||||
await fs.copy(pnpmWorkspaceSrc, pnpmWorkspaceDest);
|
await processTemplate(pnpmWorkspaceSrc, pnpmWorkspaceDest, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,15 @@ import handlebars from "handlebars";
|
|||||||
import type { ProjectConfig } from "../types";
|
import type { ProjectConfig } from "../types";
|
||||||
import { formatFileWithBiome } from "./biome-formatter";
|
import { formatFileWithBiome } from "./biome-formatter";
|
||||||
|
|
||||||
|
const BINARY_EXTENSIONS = new Set([
|
||||||
|
".png", ".ico", ".svg",
|
||||||
|
]);
|
||||||
|
|
||||||
|
function isBinaryFile(filePath: string): boolean {
|
||||||
|
const ext = path.extname(filePath).toLowerCase();
|
||||||
|
return BINARY_EXTENSIONS.has(ext);
|
||||||
|
}
|
||||||
|
|
||||||
export async function processTemplate(
|
export async function processTemplate(
|
||||||
srcPath: string,
|
srcPath: string,
|
||||||
destPath: string,
|
destPath: string,
|
||||||
@@ -13,6 +22,11 @@ export async function processTemplate(
|
|||||||
try {
|
try {
|
||||||
await fs.ensureDir(path.dirname(destPath));
|
await fs.ensureDir(path.dirname(destPath));
|
||||||
|
|
||||||
|
if (isBinaryFile(srcPath) && !srcPath.endsWith(".hbs")) {
|
||||||
|
await fs.copy(srcPath, destPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let content: string;
|
let content: string;
|
||||||
|
|
||||||
if (srcPath.endsWith(".hbs")) {
|
if (srcPath.endsWith(".hbs")) {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { createAuthClient } from "better-auth/react";
|
|
||||||
import { expoClient } from "@better-auth/expo/client";
|
import { expoClient } from "@better-auth/expo/client";
|
||||||
|
import { createAuthClient } from "better-auth/react";
|
||||||
import * as SecureStore from "expo-secure-store";
|
import * as SecureStore from "expo-secure-store";
|
||||||
|
|
||||||
export const authClient = createAuthClient({
|
export const authClient = createAuthClient({
|
||||||
baseURL: process.env.EXPO_PUBLIC_SERVER_URL,
|
baseURL: process.env.EXPO_PUBLIC_SERVER_URL,
|
||||||
plugins: [
|
plugins: [
|
||||||
expoClient({
|
expoClient({
|
||||||
storagePrefix: "my-better-t-app",
|
scheme: "mybettertapp",
|
||||||
|
storagePrefix: "{{projectName}}",
|
||||||
storage: SecureStore,
|
storage: SecureStore,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const auth = betterAuth({
|
|||||||
trustedOrigins: [
|
trustedOrigins: [
|
||||||
process.env.CORS_ORIGIN || "",
|
process.env.CORS_ORIGIN || "",
|
||||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||||
"my-better-t-app://",
|
"mybettertapp://", "exp://"
|
||||||
{{/if}}
|
{{/if}}
|
||||||
],
|
],
|
||||||
emailAndPassword: {
|
emailAndPassword: {
|
||||||
@@ -55,7 +55,7 @@ export const auth = betterAuth({
|
|||||||
trustedOrigins: [
|
trustedOrigins: [
|
||||||
process.env.CORS_ORIGIN || "",
|
process.env.CORS_ORIGIN || "",
|
||||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||||
"my-better-t-app://",
|
"mybettertapp://", "exp://"
|
||||||
{{/if}}
|
{{/if}}
|
||||||
],
|
],
|
||||||
emailAndPassword: {
|
emailAndPassword: {
|
||||||
@@ -124,7 +124,7 @@ export const auth = betterAuth({
|
|||||||
trustedOrigins: [
|
trustedOrigins: [
|
||||||
process.env.CORS_ORIGIN || "",
|
process.env.CORS_ORIGIN || "",
|
||||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||||
"my-better-t-app://",
|
"mybettertapp://", "exp://"
|
||||||
{{/if}}
|
{{/if}}
|
||||||
],
|
],
|
||||||
emailAndPassword: {
|
emailAndPassword: {
|
||||||
@@ -154,7 +154,7 @@ export const auth = betterAuth({
|
|||||||
trustedOrigins: [
|
trustedOrigins: [
|
||||||
process.env.CORS_ORIGIN || "",
|
process.env.CORS_ORIGIN || "",
|
||||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||||
"my-better-t-app://",
|
"mybettertapp://", "exp://"
|
||||||
{{/if}}
|
{{/if}}
|
||||||
],
|
],
|
||||||
emailAndPassword: {
|
emailAndPassword: {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "15.5.0",
|
"next": "15.5.0",
|
||||||
"react": "^19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"dotenv": "^17.2.1"
|
"dotenv": "^17.2.1"
|
||||||
},
|
},
|
||||||
{{#if (eq dbSetup 'supabase')}}
|
{{#if (eq dbSetup 'supabase')}}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "~19.1.10",
|
||||||
"zod": "^4.0.13",
|
"zod": "^4.0.13",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 384 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 46 KiB |
@@ -1,2 +0,0 @@
|
|||||||
// @ts-ignore
|
|
||||||
/// <reference types="nativewind/types" />
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"expo": {
|
|
||||||
"name": "my-better-t-app",
|
|
||||||
"slug": "my-better-t-app",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"scheme": "my-better-t-app",
|
|
||||||
"web": {
|
|
||||||
"bundler": "metro",
|
|
||||||
"output": "static",
|
|
||||||
"favicon": "./assets/favicon.png"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"expo-router",
|
|
||||||
"expo-secure-store",
|
|
||||||
"expo-web-browser"
|
|
||||||
],
|
|
||||||
"experiments": {
|
|
||||||
"typedRoutes": true,
|
|
||||||
"tsconfigPaths": true
|
|
||||||
},
|
|
||||||
"newArchEnabled": true,
|
|
||||||
"orientation": "portrait",
|
|
||||||
"icon": "./assets/icon.png",
|
|
||||||
"userInterfaceStyle": "light",
|
|
||||||
"splash": {
|
|
||||||
"image": "./assets/splash.png",
|
|
||||||
"resizeMode": "contain",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"assetBundlePatterns": [
|
|
||||||
"**/*"
|
|
||||||
],
|
|
||||||
"ios": {
|
|
||||||
"supportsTablet": true,
|
|
||||||
"bundleIdentifier": "com.amanvarshney01.mybettertapp"
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"adaptiveIcon": {
|
|
||||||
"foregroundImage": "./assets/adaptive-icon.png",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"package": "com.amanvarshney01.mybettertapp",
|
|
||||||
"edgeToEdgeEnabled": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
49
apps/cli/templates/frontend/native/nativewind/app.json.hbs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "{{projectName}}",
|
||||||
|
"slug": "{{projectName}}",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/images/icon.png",
|
||||||
|
"scheme": "mybettertapp",
|
||||||
|
"userInterfaceStyle": "automatic",
|
||||||
|
"newArchEnabled": true,
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"backgroundColor": "#E6F4FE",
|
||||||
|
"foregroundImage": "./assets/images/android-icon-foreground.png",
|
||||||
|
"backgroundImage": "./assets/images/android-icon-background.png",
|
||||||
|
"monochromeImage": "./assets/images/android-icon-monochrome.png"
|
||||||
|
},
|
||||||
|
"edgeToEdgeEnabled": true,
|
||||||
|
"predictiveBackGestureEnabled": false,
|
||||||
|
"package": "com.anonymous.mybettertapp"
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"output": "static",
|
||||||
|
"favicon": "./assets/images/favicon.png"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"expo-router",
|
||||||
|
[
|
||||||
|
"expo-splash-screen",
|
||||||
|
{
|
||||||
|
"image": "./assets/images/splash-icon.png",
|
||||||
|
"imageWidth": 200,
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"dark": {
|
||||||
|
"backgroundColor": "#000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"experiments": {
|
||||||
|
"typedRoutes": true,
|
||||||
|
"reactCompiler": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ export default function TabLayout() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
screenOptions={{
|
screenOptions=\{{
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
tabBarActiveTintColor: isDarkColorScheme
|
tabBarActiveTintColor: isDarkColorScheme
|
||||||
? "hsl(217.2 91.2% 59.8%)"
|
? "hsl(217.2 91.2% 59.8%)"
|
||||||
@@ -27,14 +27,14 @@ export default function TabLayout() {
|
|||||||
>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="index"
|
name="index"
|
||||||
options={{
|
options=\{{
|
||||||
title: "Home",
|
title: "Home",
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="two"
|
name="two"
|
||||||
options={{
|
options=\{{
|
||||||
title: "Explore",
|
title: "Explore",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
<TabBarIcon name="compass" color={color} />
|
<TabBarIcon name="compass" color={color} />
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { ScrollViewStyleReset } from 'expo-router/html';
|
|
||||||
import { ReactNode } from 'react';
|
|
||||||
|
|
||||||
// This file is web-only and used to configure the root HTML for every
|
|
||||||
// web page during static rendering.
|
|
||||||
// The contents of this function only run in Node.js environments and
|
|
||||||
// do not have access to the DOM or browser APIs.
|
|
||||||
export default function Root({ children }: { children: ReactNode }) {
|
|
||||||
return (
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charSet="utf-8" />
|
|
||||||
<meta content="IE=edge" httpEquiv="X-UA-Compatible" />
|
|
||||||
|
|
||||||
{/*
|
|
||||||
This viewport disables scaling which makes the mobile website act more like a native app.
|
|
||||||
However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
||||||
*/}
|
|
||||||
<meta
|
|
||||||
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
|
|
||||||
name="viewport"
|
|
||||||
/>
|
|
||||||
{/*
|
|
||||||
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
|
|
||||||
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
|
|
||||||
*/}
|
|
||||||
<ScrollViewStyleReset />
|
|
||||||
|
|
||||||
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
|
|
||||||
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
|
|
||||||
{/* Add any additional <head> elements that you want globally available on web... */}
|
|
||||||
</head>
|
|
||||||
<body>{children}</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const responsiveBackground = `
|
|
||||||
body {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #000;
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
@@ -5,7 +5,7 @@ import { Text, View } from "react-native";
|
|||||||
export default function NotFoundScreen() {
|
export default function NotFoundScreen() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen options={{ title: "Oops!" }} />
|
<Stack.Screen options=\{{ title: "Oops!" }} />
|
||||||
<Container>
|
<Container>
|
||||||
<View className="flex-1 justify-center items-center p-6">
|
<View className="flex-1 justify-center items-center p-6">
|
||||||
<View className="items-center">
|
<View className="items-center">
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
module.exports = function (api) {
|
|
||||||
api.cache(true);
|
|
||||||
const plugins = [];
|
|
||||||
|
|
||||||
plugins.push('react-native-reanimated/plugin');
|
|
||||||
|
|
||||||
return {
|
|
||||||
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
|
|
||||||
plugins,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
module.exports = (api) => {
|
||||||
|
api.cache(true);
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
plugins.push("react-native-worklets/plugin");
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets: [
|
||||||
|
["babel-preset-expo", { jsxImportSource: "nativewind" }],
|
||||||
|
"nativewind/babel",
|
||||||
|
],
|
||||||
|
plugins,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { SafeAreaView } from "react-native";
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
|
||||||
export const Container = ({ children }: { children: React.ReactNode }) => {
|
export const Container = ({ children }: { children: React.ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
@@ -16,7 +16,7 @@ export const HeaderButton = forwardRef<
|
|||||||
name="info-circle"
|
name="info-circle"
|
||||||
size={20}
|
size={20}
|
||||||
className="text-secondary-foreground"
|
className="text-secondary-foreground"
|
||||||
style={{
|
style=\{{
|
||||||
opacity: pressed ? 0.7 : 1,
|
opacity: pressed ? 0.7 : 1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -4,5 +4,5 @@ export const TabBarIcon = (props: {
|
|||||||
name: React.ComponentProps<typeof FontAwesome>["name"];
|
name: React.ComponentProps<typeof FontAwesome>["name"];
|
||||||
color: string;
|
color: string;
|
||||||
}) => {
|
}) => {
|
||||||
return <FontAwesome size={24} style={{ marginBottom: -3 }} {...props} />;
|
return <FontAwesome size={24} style=\{{ marginBottom: -3 }} {...props} />;
|
||||||
};
|
};
|
||||||
@@ -10,39 +10,41 @@
|
|||||||
"web": "expo start --web"
|
"web": "expo start --web"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.0.4",
|
"@expo/vector-icons": "^15.0.2",
|
||||||
"@react-navigation/bottom-tabs": "^7.2.0",
|
"@react-navigation/bottom-tabs": "^7.2.0",
|
||||||
"@react-navigation/drawer": "^7.1.1",
|
"@react-navigation/drawer": "^7.1.1",
|
||||||
"@react-navigation/native": "^7.0.14",
|
"@react-navigation/native": "^7.0.14",
|
||||||
"@tanstack/react-form": "^1.0.5",
|
"@tanstack/react-form": "^1.0.5",
|
||||||
"@tanstack/react-query": "^5.69.2",
|
"@tanstack/react-query": "^5.85.5",
|
||||||
{{#if (includes examples "ai")}}
|
{{#if (includes examples "ai")}}
|
||||||
"@stardazed/streams-text-encoding": "^1.0.2",
|
"@stardazed/streams-text-encoding": "^1.0.2",
|
||||||
"@ungap/structured-clone": "^1.3.0",
|
"@ungap/structured-clone": "^1.3.0",
|
||||||
{{/if}}
|
{{/if}}
|
||||||
"expo": "^53.0.4",
|
"expo": "^54.0.1",
|
||||||
"expo-constants": "~17.1.4",
|
"expo-constants": "~18.0.8",
|
||||||
"expo-crypto": "~14.1.5",
|
"expo-crypto": "~15.0.6",
|
||||||
"expo-linking": "~7.1.4",
|
"expo-linking": "~8.0.7",
|
||||||
"expo-navigation-bar": "~4.2.3",
|
"expo-navigation-bar": "~5.0.8",
|
||||||
"expo-router": "~5.0.3",
|
"expo-router": "~6.0.0",
|
||||||
"expo-secure-store": "~14.2.3",
|
"expo-secure-store": "~15.0.6",
|
||||||
"expo-status-bar": "~2.2.3",
|
"expo-splash-screen": "~31.0.8",
|
||||||
"expo-system-ui": "~5.0.6",
|
"expo-status-bar": "~3.0.7",
|
||||||
"expo-web-browser": "~14.1.6",
|
"expo-system-ui": "~6.0.7",
|
||||||
|
"expo-web-browser": "~15.0.6",
|
||||||
"nativewind": "^4.1.23",
|
"nativewind": "^4.1.23",
|
||||||
"react": "19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.79.1",
|
"react-native": "0.81.4",
|
||||||
"react-native-gesture-handler": "~2.24.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "~4.1.0",
|
||||||
"react-native-safe-area-context": "5.3.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
"react-native-screens": "~4.10.0",
|
"react-native-screens": "~4.16.0",
|
||||||
"react-native-web": "^0.20.0"
|
"react-native-web": "^0.21.0",
|
||||||
|
"react-native-worklets": "^0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.10",
|
"@babel/core": "^7.26.10",
|
||||||
"@types/react": "~19.0.10",
|
"@types/react": "~19.1.10",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "~5.8.2"
|
"typescript": "~5.8.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
const { hairlineWidth } = require("nativewind/theme");
|
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
darkMode: "class",
|
|
||||||
content: ["./app/**/*.{js,ts,tsx}", "./components/**/*.{js,ts,tsx}"],
|
|
||||||
|
|
||||||
presets: [require("nativewind/preset")],
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
background: "hsl(var(--background))",
|
|
||||||
foreground: "hsl(var(--foreground))",
|
|
||||||
card: {
|
|
||||||
DEFAULT: "hsl(var(--card))",
|
|
||||||
foreground: "hsl(var(--card-foreground))",
|
|
||||||
},
|
|
||||||
popover: {
|
|
||||||
DEFAULT: "hsl(var(--popover))",
|
|
||||||
foreground: "hsl(var(--popover-foreground))",
|
|
||||||
},
|
|
||||||
primary: {
|
|
||||||
DEFAULT: "hsl(var(--primary))",
|
|
||||||
foreground: "hsl(var(--primary-foreground))",
|
|
||||||
},
|
|
||||||
secondary: {
|
|
||||||
DEFAULT: "hsl(var(--secondary))",
|
|
||||||
foreground: "hsl(var(--secondary-foreground))",
|
|
||||||
},
|
|
||||||
muted: {
|
|
||||||
DEFAULT: "hsl(var(--muted))",
|
|
||||||
foreground: "hsl(var(--muted-foreground))",
|
|
||||||
},
|
|
||||||
accent: {
|
|
||||||
DEFAULT: "hsl(var(--accent))",
|
|
||||||
foreground: "hsl(var(--accent-foreground))",
|
|
||||||
},
|
|
||||||
destructive: {
|
|
||||||
DEFAULT: "hsl(var(--destructive))",
|
|
||||||
foreground: "hsl(var(--destructive-foreground))",
|
|
||||||
},
|
|
||||||
border: "hsl(var(--border))",
|
|
||||||
input: "hsl(var(--input))",
|
|
||||||
ring: "hsl(var(--ring))",
|
|
||||||
radius: "var(--radius)",
|
|
||||||
},
|
|
||||||
borderRadius: {
|
|
||||||
xl: "calc(var(--radius) + 4px)",
|
|
||||||
lg: "var(--radius)",
|
|
||||||
md: "calc(var(--radius) - 2px)",
|
|
||||||
sm: "calc(var(--radius) - 4px)",
|
|
||||||
},
|
|
||||||
borderWidth: {
|
|
||||||
hairline: hairlineWidth(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [],
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { hairlineWidth } from "nativewind/theme";
|
||||||
|
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export const darkMode = "class";
|
||||||
|
export const content = [
|
||||||
|
"./app/**/*.{js,ts,tsx}",
|
||||||
|
"./components/**/*.{js,ts,tsx}",
|
||||||
|
];
|
||||||
|
export const presets = [require("nativewind/preset")];
|
||||||
|
export const theme = {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
background: "hsl(var(--background))",
|
||||||
|
foreground: "hsl(var(--foreground))",
|
||||||
|
card: {
|
||||||
|
DEFAULT: "hsl(var(--card))",
|
||||||
|
foreground: "hsl(var(--card-foreground))",
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
DEFAULT: "hsl(var(--popover))",
|
||||||
|
foreground: "hsl(var(--popover-foreground))",
|
||||||
|
},
|
||||||
|
primary: {
|
||||||
|
DEFAULT: "hsl(var(--primary))",
|
||||||
|
foreground: "hsl(var(--primary-foreground))",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: "hsl(var(--secondary))",
|
||||||
|
foreground: "hsl(var(--secondary-foreground))",
|
||||||
|
},
|
||||||
|
muted: {
|
||||||
|
DEFAULT: "hsl(var(--muted))",
|
||||||
|
foreground: "hsl(var(--muted-foreground))",
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: "hsl(var(--accent))",
|
||||||
|
foreground: "hsl(var(--accent-foreground))",
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
DEFAULT: "hsl(var(--destructive))",
|
||||||
|
foreground: "hsl(var(--destructive-foreground))",
|
||||||
|
},
|
||||||
|
border: "hsl(var(--border))",
|
||||||
|
input: "hsl(var(--input))",
|
||||||
|
ring: "hsl(var(--ring))",
|
||||||
|
radius: "var(--radius)",
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
xl: "calc(var(--radius) + 4px)",
|
||||||
|
lg: "var(--radius)",
|
||||||
|
md: "calc(var(--radius) - 2px)",
|
||||||
|
sm: "calc(var(--radius) - 4px)",
|
||||||
|
},
|
||||||
|
borderWidth: {
|
||||||
|
hairline: hairlineWidth(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const plugins = [];
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"expo": {
|
|
||||||
"name": "my-better-t-app",
|
|
||||||
"slug": "my-better-t-app",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"newArchEnabled": true,
|
|
||||||
"scheme": "my-better-t-app",
|
|
||||||
"web": {
|
|
||||||
"bundler": "metro",
|
|
||||||
"output": "static",
|
|
||||||
"favicon": "./assets/favicon.png"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"expo-router",
|
|
||||||
"react-native-edge-to-edge",
|
|
||||||
"expo-secure-store"
|
|
||||||
],
|
|
||||||
"experiments": {
|
|
||||||
"typedRoutes": true,
|
|
||||||
"tsconfigPaths": true,
|
|
||||||
"reactCompiler": true
|
|
||||||
},
|
|
||||||
"orientation": "portrait",
|
|
||||||
"icon": "./assets/icon.png",
|
|
||||||
"userInterfaceStyle": "automatic",
|
|
||||||
"splash": {
|
|
||||||
"image": "./assets/splash.png",
|
|
||||||
"resizeMode": "contain",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"assetBundlePatterns": ["**/*"],
|
|
||||||
"ios": {
|
|
||||||
"supportsTablet": true,
|
|
||||||
"bundleIdentifier": "com.amanvarshney01.mybettertapp"
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"adaptiveIcon": {
|
|
||||||
"foregroundImage": "./assets/adaptive-icon.png",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"package": "com.amanvarshney01.mybettertapp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
49
apps/cli/templates/frontend/native/unistyles/app.json.hbs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "{{projectName}}",
|
||||||
|
"slug": "{{projectName}}",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/images/icon.png",
|
||||||
|
"scheme": "mybettertapp",
|
||||||
|
"userInterfaceStyle": "automatic",
|
||||||
|
"newArchEnabled": true,
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"backgroundColor": "#E6F4FE",
|
||||||
|
"foregroundImage": "./assets/images/android-icon-foreground.png",
|
||||||
|
"backgroundImage": "./assets/images/android-icon-background.png",
|
||||||
|
"monochromeImage": "./assets/images/android-icon-monochrome.png"
|
||||||
|
},
|
||||||
|
"edgeToEdgeEnabled": true,
|
||||||
|
"predictiveBackGestureEnabled": false,
|
||||||
|
"package": "com.anonymous.mybettertapp6"
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"output": "static",
|
||||||
|
"favicon": "./assets/images/favicon.png"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"expo-router",
|
||||||
|
[
|
||||||
|
"expo-splash-screen",
|
||||||
|
{
|
||||||
|
"image": "./assets/images/splash-icon.png",
|
||||||
|
"imageWidth": 200,
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"dark": {
|
||||||
|
"backgroundColor": "#000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"experiments": {
|
||||||
|
"typedRoutes": true,
|
||||||
|
"reactCompiler": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ export default function TabLayout() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
screenOptions={{
|
screenOptions=\{{
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
tabBarActiveTintColor: theme.colors.primary,
|
tabBarActiveTintColor: theme.colors.primary,
|
||||||
tabBarInactiveTintColor: theme.colors.mutedForeground,
|
tabBarInactiveTintColor: theme.colors.mutedForeground,
|
||||||
@@ -20,14 +20,14 @@ export default function TabLayout() {
|
|||||||
>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="index"
|
name="index"
|
||||||
options={{
|
options=\{{
|
||||||
title: "Home",
|
title: "Home",
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="two"
|
name="two"
|
||||||
options={{
|
options=\{{
|
||||||
title: "Explore",
|
title: "Explore",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
<TabBarIcon name="compass" color={color} />
|
<TabBarIcon name="compass" color={color} />
|
||||||
@@ -46,9 +46,7 @@ export default function Home() {
|
|||||||
contentContainerStyle={styles.container}
|
contentContainerStyle={styles.container}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
<Text className="font-mono text-foreground text-3xl font-bold mb-4">
|
<Text style={styles.heroTitle}>BETTER T STACK</Text>
|
||||||
BETTER T STACK
|
|
||||||
</Text>
|
|
||||||
<View style={styles.statusCard}>
|
<View style={styles.statusCard}>
|
||||||
<View style={styles.statusHeader}>
|
<View style={styles.statusHeader}>
|
||||||
<Text style={styles.statusTitle}>System Status</Text>
|
<Text style={styles.statusTitle}>System Status</Text>
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import { ScrollViewStyleReset } from 'expo-router/html';
|
|
||||||
|
|
||||||
import '../unistyles';
|
|
||||||
|
|
||||||
// This file is web-only and used to configure the root HTML for every
|
|
||||||
// web page during static rendering.
|
|
||||||
// The contents of this function only run in Node.js environments and
|
|
||||||
// do not have access to the DOM or browser APIs.
|
|
||||||
export default function Root({ children }: { children: React.ReactNode }) {
|
|
||||||
return (
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charSet="utf-8" />
|
|
||||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
|
|
||||||
{/*
|
|
||||||
This viewport disables scaling which makes the mobile website act more like a native app.
|
|
||||||
However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
||||||
*/}
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
|
|
||||||
/>
|
|
||||||
{/*
|
|
||||||
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
|
|
||||||
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
|
|
||||||
*/}
|
|
||||||
<ScrollViewStyleReset />
|
|
||||||
|
|
||||||
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
|
|
||||||
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
|
|
||||||
{/* Add any additional <head> elements that you want globally available on web... */}
|
|
||||||
</head>
|
|
||||||
<body>{children}</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const responsiveBackground = `
|
|
||||||
body {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #000;
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Container } from "@/components/container";
|
|
||||||
import { Link, Stack } from "expo-router";
|
import { Link, Stack } from "expo-router";
|
||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
import { StyleSheet } from "react-native-unistyles";
|
import { StyleSheet } from "react-native-unistyles";
|
||||||
|
import { Container } from "@/components/container";
|
||||||
|
|
||||||
export default function NotFoundScreen() {
|
export default function NotFoundScreen() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen options={{ title: "Oops!" }} />
|
<Stack.Screen options=\{{ title: "Oops!" }} />
|
||||||
<Container>
|
<Container>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
@@ -22,14 +22,14 @@ import { QueryClientProvider } from "@tanstack/react-query";
|
|||||||
import { Stack } from "expo-router";
|
import { Stack } from "expo-router";
|
||||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||||
import { useUnistyles } from "react-native-unistyles";
|
import { useUnistyles } from "react-native-unistyles";
|
||||||
|
import { StatusBar } from "expo-status-bar";
|
||||||
|
|
||||||
export const unstable_settings = {
|
export const unstable_settings = {
|
||||||
// Ensure that reloading on `/modal` keeps a back button present.
|
|
||||||
initialRouteName: "(drawer)",
|
initialRouteName: "(drawer)",
|
||||||
};
|
};
|
||||||
|
|
||||||
{{#if (eq backend "convex")}}
|
{{#if (eq backend "convex")}}
|
||||||
const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, {
|
const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL || "", {
|
||||||
unsavedChangesWarning: false,
|
unsavedChangesWarning: false,
|
||||||
});
|
});
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
module.exports = function (api) {
|
|
||||||
api.cache(true);
|
|
||||||
const plugins = [];
|
|
||||||
|
|
||||||
plugins.push([
|
|
||||||
'react-native-unistyles/plugin',
|
|
||||||
{
|
|
||||||
root: "src",
|
|
||||||
autoProcessRoot: 'app',
|
|
||||||
autoProcessImports: ['@/components']
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
plugins.push('react-native-reanimated/plugin');
|
|
||||||
|
|
||||||
return {
|
|
||||||
presets: ['babel-preset-expo'],
|
|
||||||
|
|
||||||
plugins,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
module.exports = (api) => {
|
||||||
|
api.cache(true);
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
plugins.push([
|
||||||
|
"react-native-unistyles/plugin",
|
||||||
|
{
|
||||||
|
root: "src",
|
||||||
|
autoProcessRoot: "app",
|
||||||
|
autoProcessImports: ["@/components"],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
plugins.push("react-native-worklets/plugin");
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets: ["babel-preset-expo"],
|
||||||
|
|
||||||
|
plugins,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { SafeAreaView } from "react-native";
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
import { StyleSheet } from "react-native-unistyles";
|
import { StyleSheet } from "react-native-unistyles";
|
||||||
|
|
||||||
export const Container = ({ children }: { children: React.ReactNode }) => {
|
export const Container = ({ children }: { children: React.ReactNode }) => {
|
||||||
@@ -14,7 +14,7 @@ export const HeaderButton = forwardRef<
|
|||||||
name="info-circle"
|
name="info-circle"
|
||||||
size={20}
|
size={20}
|
||||||
color={styles.icon.color}
|
color={styles.icon.color}
|
||||||
style={{
|
style=\{{
|
||||||
opacity: pressed ? 0.7 : 1,
|
opacity: pressed ? 0.7 : 1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -4,5 +4,5 @@ export const TabBarIcon = (props: {
|
|||||||
name: React.ComponentProps<typeof FontAwesome>["name"];
|
name: React.ComponentProps<typeof FontAwesome>["name"];
|
||||||
color: string;
|
color: string;
|
||||||
}) => {
|
}) => {
|
||||||
return <FontAwesome size={24} style={{ marginBottom: -3 }} {...props} />;
|
return <FontAwesome size={24} style=\{{ marginBottom: -3 }} {...props} />;
|
||||||
};
|
};
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
/// <reference types="expo/types" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited and should be in your git ignore
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
|
||||||
const { getDefaultConfig } = require("expo/metro-config");
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
const workspaceRoot = path.resolve(__dirname, "../..");
|
|
||||||
const projectRoot = __dirname;
|
|
||||||
|
|
||||||
const config = getDefaultConfig(projectRoot);
|
|
||||||
|
|
||||||
// 1. Watch all files within the monorepo
|
|
||||||
config.watchFolders = [workspaceRoot];
|
|
||||||
// 2. Let Metro know where to resolve packages, and in what order
|
|
||||||
config.resolver.nodeModulesPaths = [
|
|
||||||
path.resolve(projectRoot, "node_modules"),
|
|
||||||
path.resolve(workspaceRoot, "node_modules"),
|
|
||||||
];
|
|
||||||
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
|
|
||||||
config.resolver.disableHierarchicalLookup = true;
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const { getDefaultConfig } = require("expo/metro-config");
|
||||||
|
|
||||||
|
const config = getDefaultConfig(__dirname);
|
||||||
|
|
||||||
|
module.exports = config;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "native",
|
"name": "native",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "expo start --clear",
|
"dev": "expo start --clear",
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
"web": "expo start --web"
|
"web": "expo start --web"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.1.0",
|
"@expo/vector-icons": "^15.0.2",
|
||||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||||
"@react-navigation/drawer": "^7.3.9",
|
"@react-navigation/drawer": "^7.3.9",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
@@ -17,35 +18,35 @@
|
|||||||
"@stardazed/streams-text-encoding": "^1.0.2",
|
"@stardazed/streams-text-encoding": "^1.0.2",
|
||||||
"@ungap/structured-clone": "^1.3.0",
|
"@ungap/structured-clone": "^1.3.0",
|
||||||
{{/if}}
|
{{/if}}
|
||||||
"@tanstack/react-form": "^1.14.0",
|
"@tanstack/react-form": "^1.0.5",
|
||||||
"babel-plugin-react-compiler": "^19.1.0-rc.2",
|
"expo": "^54.0.0",
|
||||||
"expo": "^53.0.17",
|
"expo-constants": "~18.0.8",
|
||||||
"expo-constants": "~17.1.7",
|
"expo-crypto": "~15.0.6",
|
||||||
"expo-crypto": "~14.1.5",
|
"expo-linking": "~8.0.7",
|
||||||
"expo-linking": "~7.1.7",
|
"expo-router": "~6.0.0",
|
||||||
"expo-router": "~5.1.3",
|
"expo-secure-store": "~15.0.6",
|
||||||
"expo-secure-store": "~14.2.3",
|
"expo-splash-screen": "~31.0.8",
|
||||||
"expo-status-bar": "~2.2.3",
|
"expo-status-bar": "^3.0.7",
|
||||||
"expo-system-ui": "~5.0.10",
|
"expo-system-ui": "~6.0.7",
|
||||||
"expo-dev-client": "~5.2.4",
|
"expo-dev-client": "~6.0.11",
|
||||||
"expo-web-browser": "~14.2.0",
|
"expo-web-browser": "~15.0.6",
|
||||||
"react": "19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.79.5",
|
"react-native": "0.81.4",
|
||||||
"react-native-edge-to-edge": "1.6.0",
|
"react-native-edge-to-edge": "^1.7.0",
|
||||||
"react-native-gesture-handler": "~2.24.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-nitro-modules": "0.26.3",
|
"react-native-nitro-modules": "^0.29.4",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "~4.1.0",
|
||||||
"react-native-safe-area-context": "5.4.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
"react-native-screens": "~4.11.1",
|
"react-native-screens": "~4.16.0",
|
||||||
"react-native-unistyles": "^3.0.0",
|
"react-native-unistyles": "^3.0.12",
|
||||||
"react-native-web": "^0.20.0"
|
"react-native-web": "^0.21.0",
|
||||||
|
"react-native-worklets": "^0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ajv": "^8.17.1",
|
"ajv": "^8.17.1",
|
||||||
"@babel/core": "^7.28.0",
|
"@babel/core": "^7.28.0",
|
||||||
"@types/react": "~19.0.10",
|
"@types/react": "~19.1.10",
|
||||||
"typescript": "~5.8.3"
|
"typescript": "~5.9.2"
|
||||||
},
|
}
|
||||||
"private": true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
const sharedColors = {
|
|
||||||
success: "#22C55E",
|
|
||||||
destructive: "#EF4444",
|
|
||||||
warning: "#F59E0B",
|
|
||||||
info: "#3B82F6",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const lightTheme = {
|
|
||||||
colors: {
|
|
||||||
...sharedColors,
|
|
||||||
typography: "hsl(222.2 84% 4.9%)",
|
|
||||||
background: "hsl(0 0% 100%)",
|
|
||||||
foreground: "hsl(222.2 84% 4.9%)",
|
|
||||||
card: "hsl(0 0% 100%)",
|
|
||||||
cardForeground: "hsl(222.2 84% 4.9%)",
|
|
||||||
primary: "hsl(221.2 83.2% 53.3%)",
|
|
||||||
primaryForeground: "hsl(210 40% 98%)",
|
|
||||||
secondary: "hsl(210 40% 96%)",
|
|
||||||
secondaryForeground: "hsl(222.2 84% 4.9%)",
|
|
||||||
muted: "hsl(210 40% 96%)",
|
|
||||||
mutedForeground: "hsl(215.4 16.3% 46.9%)",
|
|
||||||
accent: "hsl(210 40% 96%)",
|
|
||||||
accentForeground: "hsl(222.2 84% 4.9%)",
|
|
||||||
border: "hsl(214.3 31.8% 91.4%)",
|
|
||||||
input: "hsl(214.3 31.8% 91.4%)",
|
|
||||||
ring: "hsl(221.2 83.2% 53.3%)",
|
|
||||||
},
|
|
||||||
spacing: {
|
|
||||||
xs: 4,
|
|
||||||
sm: 8,
|
|
||||||
md: 16,
|
|
||||||
lg: 24,
|
|
||||||
xl: 32,
|
|
||||||
xxl: 48,
|
|
||||||
},
|
|
||||||
borderRadius: {
|
|
||||||
sm: 6,
|
|
||||||
md: 8,
|
|
||||||
lg: 12,
|
|
||||||
xl: 16,
|
|
||||||
},
|
|
||||||
fontSize: {
|
|
||||||
xs: 12,
|
|
||||||
sm: 14,
|
|
||||||
base: 16,
|
|
||||||
lg: 18,
|
|
||||||
xl: 20,
|
|
||||||
"2xl": 24,
|
|
||||||
"3xl": 30,
|
|
||||||
"4xl": 36,
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const darkTheme = {
|
|
||||||
colors: {
|
|
||||||
...sharedColors,
|
|
||||||
typography: "hsl(210 40% 98%)",
|
|
||||||
background: "hsl(222.2 84% 4.9%)",
|
|
||||||
foreground: "hsl(210 40% 98%)",
|
|
||||||
card: "hsl(222.2 84% 4.9%)",
|
|
||||||
cardForeground: "hsl(210 40% 98%)",
|
|
||||||
primary: "hsl(217.2 91.2% 59.8%)",
|
|
||||||
primaryForeground: "hsl(222.2 84% 4.9%)",
|
|
||||||
secondary: "hsl(217.2 32.6% 17.5%)",
|
|
||||||
secondaryForeground: "hsl(210 40% 98%)",
|
|
||||||
muted: "hsl(217.2 32.6% 17.5%)",
|
|
||||||
mutedForeground: "hsl(215 20.2% 65.1%)",
|
|
||||||
accent: "hsl(217.2 32.6% 17.5%)",
|
|
||||||
accentForeground: "hsl(210 40% 98%)",
|
|
||||||
border: "hsl(217.2 32.6% 17.5%)",
|
|
||||||
input: "hsl(217.2 32.6% 17.5%)",
|
|
||||||
ring: "hsl(224.3 76.3% 94.1%)",
|
|
||||||
},
|
|
||||||
spacing: {
|
|
||||||
xs: 4,
|
|
||||||
sm: 8,
|
|
||||||
md: 16,
|
|
||||||
lg: 24,
|
|
||||||
xl: 32,
|
|
||||||
xxl: 48,
|
|
||||||
},
|
|
||||||
borderRadius: {
|
|
||||||
sm: 6,
|
|
||||||
md: 8,
|
|
||||||
lg: 12,
|
|
||||||
xl: 16,
|
|
||||||
},
|
|
||||||
fontSize: {
|
|
||||||
xs: 12,
|
|
||||||
sm: 14,
|
|
||||||
base: 16,
|
|
||||||
lg: 18,
|
|
||||||
xl: 20,
|
|
||||||
"2xl": 24,
|
|
||||||
"3xl": 30,
|
|
||||||
"4xl": 36,
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
98
apps/cli/templates/frontend/native/unistyles/theme.ts.hbs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
const sharedColors = {
|
||||||
|
success: "#22C55E",
|
||||||
|
destructive: "#EF4444",
|
||||||
|
warning: "#F59E0B",
|
||||||
|
info: "#3B82F6",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const lightTheme = {
|
||||||
|
colors: {
|
||||||
|
...sharedColors,
|
||||||
|
typography: "hsl(0 0% 0%)",
|
||||||
|
background: "hsl(0 0% 100%)",
|
||||||
|
foreground: "hsl(0 0% 0%)",
|
||||||
|
card: "hsl(0 0% 98%)",
|
||||||
|
cardForeground: "hsl(0 0% 0%)",
|
||||||
|
primary: "hsl(0 0% 10%)",
|
||||||
|
primaryForeground: "hsl(0 0% 100%)",
|
||||||
|
secondary: "hsl(0 0% 95%)",
|
||||||
|
secondaryForeground: "hsl(0 0% 0%)",
|
||||||
|
muted: "hsl(0 0% 96%)",
|
||||||
|
mutedForeground: "hsl(0 0% 45%)",
|
||||||
|
accent: "hsl(0 0% 96%)",
|
||||||
|
accentForeground: "hsl(0 0% 0%)",
|
||||||
|
border: "hsl(0 0% 90%)",
|
||||||
|
input: "hsl(0 0% 90%)",
|
||||||
|
ring: "hsl(0 0% 20%)",
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
xs: 4,
|
||||||
|
sm: 8,
|
||||||
|
md: 16,
|
||||||
|
lg: 24,
|
||||||
|
xl: 32,
|
||||||
|
xxl: 48,
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
sm: 6,
|
||||||
|
md: 8,
|
||||||
|
lg: 12,
|
||||||
|
xl: 16,
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
xs: 12,
|
||||||
|
sm: 14,
|
||||||
|
base: 16,
|
||||||
|
lg: 18,
|
||||||
|
xl: 20,
|
||||||
|
"2xl": 24,
|
||||||
|
"3xl": 30,
|
||||||
|
"4xl": 36,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const darkTheme = {
|
||||||
|
colors: {
|
||||||
|
...sharedColors,
|
||||||
|
typography: "hsl(0 0% 100%)",
|
||||||
|
background: "hsl(0 0% 0%)",
|
||||||
|
foreground: "hsl(0 0% 100%)",
|
||||||
|
card: "hsl(0 0% 2%)",
|
||||||
|
cardForeground: "hsl(0 0% 100%)",
|
||||||
|
primary: "hsl(0 0% 90%)",
|
||||||
|
primaryForeground: "hsl(0 0% 0%)",
|
||||||
|
secondary: "hsl(0 0% 10%)",
|
||||||
|
secondaryForeground: "hsl(0 0% 100%)",
|
||||||
|
muted: "hsl(0 0% 8%)",
|
||||||
|
mutedForeground: "hsl(0 0% 65%)",
|
||||||
|
accent: "hsl(0 0% 8%)",
|
||||||
|
accentForeground: "hsl(0 0% 100%)",
|
||||||
|
border: "hsl(0 0% 15%)",
|
||||||
|
input: "hsl(0 0% 15%)",
|
||||||
|
ring: "hsl(0 0% 80%)",
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
xs: 4,
|
||||||
|
sm: 8,
|
||||||
|
md: 16,
|
||||||
|
lg: 24,
|
||||||
|
xl: 32,
|
||||||
|
xxl: 48,
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
sm: 6,
|
||||||
|
md: 8,
|
||||||
|
lg: 12,
|
||||||
|
xl: 16,
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
xs: 12,
|
||||||
|
sm: 14,
|
||||||
|
base: 16,
|
||||||
|
lg: 18,
|
||||||
|
xl: 20,
|
||||||
|
"2xl": 24,
|
||||||
|
"3xl": 30,
|
||||||
|
"4xl": 36,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
"lucide-react": "^0.487.0",
|
"lucide-react": "^0.487.0",
|
||||||
"next": "15.5.0",
|
"next": "15.5.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"tailwind-merge": "^3.3.1",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tw-animate-css": "^1.3.4",
|
"tw-animate-css": "^1.3.4",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.10",
|
"@tailwindcss/postcss": "^4.1.10",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"tailwindcss": "^4.1.10",
|
"tailwindcss": "^4.1.10",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
"isbot": "^5.1.28",
|
"isbot": "^5.1.28",
|
||||||
"lucide-react": "^0.511.0",
|
"lucide-react": "^0.511.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"react-router": "^7.6.1",
|
"react-router": "^7.6.1",
|
||||||
"sonner": "^2.0.3",
|
"sonner": "^2.0.3",
|
||||||
"tailwind-merge": "^3.3.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@react-router/dev": "^7.6.1",
|
"@react-router/dev": "^7.6.1",
|
||||||
"@tailwindcss/vite": "^4.1.8",
|
"@tailwindcss/vite": "^4.1.8",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"react-router-devtools": "^1.1.0",
|
"react-router-devtools": "^1.1.0",
|
||||||
"tailwindcss": "^4.1.8",
|
"tailwindcss": "^4.1.8",
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.473.0",
|
"lucide-react": "^0.473.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"tailwind-merge": "^3.3.1",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tw-animate-css": "^1.2.5",
|
"tw-animate-css": "^1.2.5",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@tanstack/react-router-devtools": "^1.114.27",
|
"@tanstack/react-router-devtools": "^1.114.27",
|
||||||
"@tanstack/router-plugin": "^1.114.27",
|
"@tanstack/router-plugin": "^1.114.27",
|
||||||
"@types/node": "^22.13.13",
|
"@types/node": "^22.13.13",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.525.0",
|
"lucide-react": "^0.525.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "19.0.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.1.0",
|
||||||
"sonner": "^2.0.3",
|
"sonner": "^2.0.3",
|
||||||
"tailwindcss": "^4.1.3",
|
"tailwindcss": "^4.1.3",
|
||||||
"tailwind-merge": "^3.3.1",
|
"tailwind-merge": "^3.3.1",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"@tanstack/react-router-devtools": "^1.121.0-alpha.27",
|
"@tanstack/react-router-devtools": "^1.121.0-alpha.27",
|
||||||
"@testing-library/dom": "^10.4.0",
|
"@testing-library/dom": "^10.4.0",
|
||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@vitejs/plugin-react": "^5.0.1",
|
"@vitejs/plugin-react": "^5.0.1",
|
||||||
"jsdom": "^26.0.0",
|
"jsdom": "^26.0.0",
|
||||||
|
|||||||