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 pnpmWorkspaceDest = path.join(projectDir, "pnpm-workspace.yaml");
|
||||
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 { 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(
|
||||
srcPath: string,
|
||||
destPath: string,
|
||||
@@ -13,6 +22,11 @@ export async function processTemplate(
|
||||
try {
|
||||
await fs.ensureDir(path.dirname(destPath));
|
||||
|
||||
if (isBinaryFile(srcPath) && !srcPath.endsWith(".hbs")) {
|
||||
await fs.copy(srcPath, destPath);
|
||||
return;
|
||||
}
|
||||
|
||||
let content: string;
|
||||
|
||||
if (srcPath.endsWith(".hbs")) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import { expoClient } from "@better-auth/expo/client";
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: process.env.EXPO_PUBLIC_SERVER_URL,
|
||||
plugins: [
|
||||
expoClient({
|
||||
storagePrefix: "my-better-t-app",
|
||||
scheme: "mybettertapp",
|
||||
storagePrefix: "{{projectName}}",
|
||||
storage: SecureStore,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -16,7 +16,7 @@ export const auth = betterAuth({
|
||||
trustedOrigins: [
|
||||
process.env.CORS_ORIGIN || "",
|
||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||
"my-better-t-app://",
|
||||
"mybettertapp://", "exp://"
|
||||
{{/if}}
|
||||
],
|
||||
emailAndPassword: {
|
||||
@@ -55,7 +55,7 @@ export const auth = betterAuth({
|
||||
trustedOrigins: [
|
||||
process.env.CORS_ORIGIN || "",
|
||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||
"my-better-t-app://",
|
||||
"mybettertapp://", "exp://"
|
||||
{{/if}}
|
||||
],
|
||||
emailAndPassword: {
|
||||
@@ -124,7 +124,7 @@ export const auth = betterAuth({
|
||||
trustedOrigins: [
|
||||
process.env.CORS_ORIGIN || "",
|
||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||
"my-better-t-app://",
|
||||
"mybettertapp://", "exp://"
|
||||
{{/if}}
|
||||
],
|
||||
emailAndPassword: {
|
||||
@@ -154,7 +154,7 @@ export const auth = betterAuth({
|
||||
trustedOrigins: [
|
||||
process.env.CORS_ORIGIN || "",
|
||||
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
||||
"my-better-t-app://",
|
||||
"mybettertapp://", "exp://"
|
||||
{{/if}}
|
||||
],
|
||||
emailAndPassword: {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "15.5.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"dotenv": "^17.2.1"
|
||||
},
|
||||
{{#if (eq dbSetup 'supabase')}}
|
||||
@@ -20,7 +20,7 @@
|
||||
{{/if}}
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react": "~19.1.10",
|
||||
"zod": "^4.0.13",
|
||||
"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 (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
screenOptions=\{{
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: isDarkColorScheme
|
||||
? "hsl(217.2 91.2% 59.8%)"
|
||||
@@ -27,14 +27,14 @@ export default function TabLayout() {
|
||||
>
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
options=\{{
|
||||
title: "Home",
|
||||
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="two"
|
||||
options={{
|
||||
options=\{{
|
||||
title: "Explore",
|
||||
tabBarIcon: ({ 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() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Oops!" }} />
|
||||
<Stack.Screen options=\{{ title: "Oops!" }} />
|
||||
<Container>
|
||||
<View className="flex-1 justify-center items-center p-6">
|
||||
<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 { SafeAreaView } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
export const Container = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
@@ -16,7 +16,7 @@ export const HeaderButton = forwardRef<
|
||||
name="info-circle"
|
||||
size={20}
|
||||
className="text-secondary-foreground"
|
||||
style={{
|
||||
style=\{{
|
||||
opacity: pressed ? 0.7 : 1,
|
||||
}}
|
||||
/>
|
||||
@@ -4,5 +4,5 @@ export const TabBarIcon = (props: {
|
||||
name: React.ComponentProps<typeof FontAwesome>["name"];
|
||||
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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^14.0.4",
|
||||
"@expo/vector-icons": "^15.0.2",
|
||||
"@react-navigation/bottom-tabs": "^7.2.0",
|
||||
"@react-navigation/drawer": "^7.1.1",
|
||||
"@react-navigation/native": "^7.0.14",
|
||||
"@tanstack/react-form": "^1.0.5",
|
||||
"@tanstack/react-query": "^5.69.2",
|
||||
"@tanstack/react-query": "^5.85.5",
|
||||
{{#if (includes examples "ai")}}
|
||||
"@stardazed/streams-text-encoding": "^1.0.2",
|
||||
"@ungap/structured-clone": "^1.3.0",
|
||||
{{/if}}
|
||||
"expo": "^53.0.4",
|
||||
"expo-constants": "~17.1.4",
|
||||
"expo-crypto": "~14.1.5",
|
||||
"expo-linking": "~7.1.4",
|
||||
"expo-navigation-bar": "~4.2.3",
|
||||
"expo-router": "~5.0.3",
|
||||
"expo-secure-store": "~14.2.3",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"expo-system-ui": "~5.0.6",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"expo": "^54.0.1",
|
||||
"expo-constants": "~18.0.8",
|
||||
"expo-crypto": "~15.0.6",
|
||||
"expo-linking": "~8.0.7",
|
||||
"expo-navigation-bar": "~5.0.8",
|
||||
"expo-router": "~6.0.0",
|
||||
"expo-secure-store": "~15.0.6",
|
||||
"expo-splash-screen": "~31.0.8",
|
||||
"expo-status-bar": "~3.0.7",
|
||||
"expo-system-ui": "~6.0.7",
|
||||
"expo-web-browser": "~15.0.6",
|
||||
"nativewind": "^4.1.23",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.1",
|
||||
"react-native-gesture-handler": "~2.24.0",
|
||||
"react-native-reanimated": "~3.17.4",
|
||||
"react-native-safe-area-context": "5.3.0",
|
||||
"react-native-screens": "~4.10.0",
|
||||
"react-native-web": "^0.20.0"
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-native": "0.81.4",
|
||||
"react-native-gesture-handler": "~2.28.0",
|
||||
"react-native-reanimated": "~4.1.0",
|
||||
"react-native-safe-area-context": "~5.6.0",
|
||||
"react-native-screens": "~4.16.0",
|
||||
"react-native-web": "^0.21.0",
|
||||
"react-native-worklets": "^0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.10",
|
||||
"@types/react": "~19.0.10",
|
||||
"@types/react": "~19.1.10",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"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 (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
screenOptions=\{{
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: theme.colors.primary,
|
||||
tabBarInactiveTintColor: theme.colors.mutedForeground,
|
||||
@@ -20,14 +20,14 @@ export default function TabLayout() {
|
||||
>
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
options=\{{
|
||||
title: "Home",
|
||||
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="two"
|
||||
options={{
|
||||
options=\{{
|
||||
title: "Explore",
|
||||
tabBarIcon: ({ color }) => (
|
||||
<TabBarIcon name="compass" color={color} />
|
||||
@@ -46,9 +46,7 @@ export default function Home() {
|
||||
contentContainerStyle={styles.container}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<Text className="font-mono text-foreground text-3xl font-bold mb-4">
|
||||
BETTER T STACK
|
||||
</Text>
|
||||
<Text style={styles.heroTitle}>BETTER T STACK</Text>
|
||||
<View style={styles.statusCard}>
|
||||
<View style={styles.statusHeader}>
|
||||
<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 { Text, View } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { Container } from "@/components/container";
|
||||
|
||||
export default function NotFoundScreen() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Oops!" }} />
|
||||
<Stack.Screen options=\{{ title: "Oops!" }} />
|
||||
<Container>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.content}>
|
||||
@@ -22,14 +22,14 @@ import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { Stack } from "expo-router";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { useUnistyles } from "react-native-unistyles";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
|
||||
export const unstable_settings = {
|
||||
// Ensure that reloading on `/modal` keeps a back button present.
|
||||
initialRouteName: "(drawer)",
|
||||
};
|
||||
|
||||
{{#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,
|
||||
});
|
||||
{{/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 { SafeAreaView } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
|
||||
export const Container = ({ children }: { children: React.ReactNode }) => {
|
||||
@@ -14,7 +14,7 @@ export const HeaderButton = forwardRef<
|
||||
name="info-circle"
|
||||
size={20}
|
||||
color={styles.icon.color}
|
||||
style={{
|
||||
style=\{{
|
||||
opacity: pressed ? 0.7 : 1,
|
||||
}}
|
||||
/>
|
||||
@@ -4,5 +4,5 @@ export const TabBarIcon = (props: {
|
||||
name: React.ComponentProps<typeof FontAwesome>["name"];
|
||||
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",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "expo start --clear",
|
||||
@@ -9,7 +10,7 @@
|
||||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^14.1.0",
|
||||
"@expo/vector-icons": "^15.0.2",
|
||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||
"@react-navigation/drawer": "^7.3.9",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
@@ -17,35 +18,35 @@
|
||||
"@stardazed/streams-text-encoding": "^1.0.2",
|
||||
"@ungap/structured-clone": "^1.3.0",
|
||||
{{/if}}
|
||||
"@tanstack/react-form": "^1.14.0",
|
||||
"babel-plugin-react-compiler": "^19.1.0-rc.2",
|
||||
"expo": "^53.0.17",
|
||||
"expo-constants": "~17.1.7",
|
||||
"expo-crypto": "~14.1.5",
|
||||
"expo-linking": "~7.1.7",
|
||||
"expo-router": "~5.1.3",
|
||||
"expo-secure-store": "~14.2.3",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"expo-system-ui": "~5.0.10",
|
||||
"expo-dev-client": "~5.2.4",
|
||||
"expo-web-browser": "~14.2.0",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.5",
|
||||
"react-native-edge-to-edge": "1.6.0",
|
||||
"react-native-gesture-handler": "~2.24.0",
|
||||
"react-native-nitro-modules": "0.26.3",
|
||||
"react-native-reanimated": "~3.17.4",
|
||||
"react-native-safe-area-context": "5.4.0",
|
||||
"react-native-screens": "~4.11.1",
|
||||
"react-native-unistyles": "^3.0.0",
|
||||
"react-native-web": "^0.20.0"
|
||||
"@tanstack/react-form": "^1.0.5",
|
||||
"expo": "^54.0.0",
|
||||
"expo-constants": "~18.0.8",
|
||||
"expo-crypto": "~15.0.6",
|
||||
"expo-linking": "~8.0.7",
|
||||
"expo-router": "~6.0.0",
|
||||
"expo-secure-store": "~15.0.6",
|
||||
"expo-splash-screen": "~31.0.8",
|
||||
"expo-status-bar": "^3.0.7",
|
||||
"expo-system-ui": "~6.0.7",
|
||||
"expo-dev-client": "~6.0.11",
|
||||
"expo-web-browser": "~15.0.6",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-native": "0.81.4",
|
||||
"react-native-edge-to-edge": "^1.7.0",
|
||||
"react-native-gesture-handler": "~2.28.0",
|
||||
"react-native-nitro-modules": "^0.29.4",
|
||||
"react-native-reanimated": "~4.1.0",
|
||||
"react-native-safe-area-context": "~5.6.0",
|
||||
"react-native-screens": "~4.16.0",
|
||||
"react-native-unistyles": "^3.0.12",
|
||||
"react-native-web": "^0.21.0",
|
||||
"react-native-worklets": "^0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ajv": "^8.17.1",
|
||||
"@babel/core": "^7.28.0",
|
||||
"@types/react": "~19.0.10",
|
||||
"typescript": "~5.8.3"
|
||||
},
|
||||
"private": true
|
||||
"@types/react": "~19.1.10",
|
||||
"typescript": "~5.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
"next": "15.5.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"sonner": "^2.0.5",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tw-animate-css": "^1.3.4",
|
||||
@@ -25,7 +25,7 @@
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.10",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react": "~19.1.10",
|
||||
"@types/react-dom": "^19",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
"isbot": "^5.1.28",
|
||||
"lucide-react": "^0.511.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-router": "^7.6.1",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "^3.3.0",
|
||||
@@ -31,7 +31,7 @@
|
||||
"@react-router/dev": "^7.6.1",
|
||||
"@tailwindcss/vite": "^4.1.8",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19.0.12",
|
||||
"@types/react": "~19.1.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"react-router-devtools": "^1.1.0",
|
||||
"tailwindcss": "^4.1.8",
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.473.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"sonner": "^2.0.5",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tw-animate-css": "^1.2.5",
|
||||
@@ -31,7 +31,7 @@
|
||||
"@tanstack/react-router-devtools": "^1.114.27",
|
||||
"@tanstack/router-plugin": "^1.114.27",
|
||||
"@types/node": "^22.13.13",
|
||||
"@types/react": "^19.0.12",
|
||||
"@types/react": "~19.1.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"postcss": "^8.5.3",
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwindcss": "^4.1.3",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
@@ -33,7 +33,7 @@
|
||||
"@tanstack/react-router-devtools": "^1.121.0-alpha.27",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@types/react": "^19.0.12",
|
||||
"@types/react": "~19.1.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^5.0.1",
|
||||
"jsdom": "^26.0.0",
|
||||
|
||||