Skip to content

Commit 49c633f

Browse files
committed
feat: use rnn theme together with unistyles theme
1 parent d905633 commit 49c633f

File tree

5 files changed

+168
-141
lines changed

5 files changed

+168
-141
lines changed

CLAUDE.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# CLAUDE.md
2+
3+
## Project Overview
4+
5+
Create Expo Stack is an interactive CLI tool that generates highly configurable, typesafe Expo React Native applications. The CLI is accessed via `npx rn-new@latest`.
6+
7+
## Architecture
8+
9+
This is a monorepo managed with Turborepo and Bun workspaces:
10+
11+
- **cli/**: Main CLI package (create-expo-stack) - the core product
12+
- **www/**: Marketing landing page with live CLI demo
13+
- **docs/**: Astro-based documentation site
14+
- **packages/rn-new**: Package for the `npx rn-new` command
15+
16+
The CLI uses EJS templates to dynamically generate project files based on user selections.
17+
18+
## Key Commands
19+
20+
### Development
21+
22+
```bash
23+
# Install dependencies (use Bun v1.2.11)
24+
bun install
25+
26+
# Build entire monorepo
27+
bun run build
28+
29+
# Build specific packages
30+
bun run build:cli # CLI package
31+
bun run build:www # Landing page
32+
bun run build:docs # Documentation
33+
34+
# Run CLI locally
35+
cd cli
36+
bun run dev
37+
38+
# Link CLI for global testing
39+
cd cli
40+
bun run build
41+
npm link # or yarn link, or pnpm link --global
42+
# Then use: create-expo-stack <PROJECT_NAME> <OPTIONS>
43+
```
44+
45+
### Testing
46+
47+
```bash
48+
cd cli
49+
bun test # Run tests (160s timeout)
50+
bun test:watch # Watch mode
51+
bun test:all # Test all package managers
52+
bun run snapshot-update # Update test snapshots
53+
```
54+
55+
### Code Quality
56+
57+
```bash
58+
# Root level formatting/linting
59+
bun run format
60+
61+
# CLI specific
62+
cd cli
63+
bun run format
64+
bun run lint-templates # Lint EJS templates
65+
```
66+
67+
## CLI Development Workflow
68+
69+
1. **Template System**: Templates are in `cli/src/templates/`:
70+
71+
- `base/`: Core files for all projects
72+
- `packages/`: Framework-specific additions
73+
- Files use EJS for conditional content
74+
75+
2. **Adding Features**: To add a new styling library, auth provider, etc.:
76+
77+
- Add templates to appropriate directory
78+
- Update CLI prompts in `cli/src/commands/create-expo-stack.ts`
79+
- Add configuration logic
80+
- Add tests
81+
82+
3. **Testing Changes**:
83+
- Link CLI globally (see commands above)
84+
- Create test projects: `create-expo-stack test-app --various-flags`
85+
- Run integration tests: `bun test`
86+
4. **Local Testing Example**:
87+
```bash
88+
cd cli
89+
bun run dev myTestProject --react-navigation --unistyles --drawer+tabs --bun --overwrite
90+
```
91+
This command tests the CLI locally with React Navigation, Unistyles styling, drawer + tabs navigation, Bun package manager, and overwrites existing project if present.
92+
93+
## Important Notes
94+
95+
### Git Hooks
96+
97+
Pre-commit hooks via Husky:
98+
99+
- Runs `lint-staged` automatically
100+
- Prompts for changeset creation when CLI files are modified
101+
102+
### Changesets
103+
104+
When making CLI changes:
105+
106+
```bash
107+
bun run changeset
108+
```
109+
110+
This creates a changeset file that should be committed with your changes.
111+
112+
### Supported Stack
113+
114+
- React Native v0.79, React v19, TypeScript v5
115+
- Expo SDK v53 with various Expo modules
116+
- Navigation: Expo Router v5, React Navigation v7
117+
- Styling: NativeWind v4.1, Tamagui v1, Restyle v2, Unistyles v3
118+
- Auth: Firebase v10, Supabase v2
119+
120+
### CLI Usage Patterns
121+
122+
```bash
123+
# Interactive mode
124+
npx rn-new@latest
125+
126+
# With flags
127+
create-expo-stack myapp --nativewind --supabase
128+
create-expo-stack myapp --default --noInstall --noGit
129+
create-expo-stack myapp --npm # specify package manager
130+
```
131+
132+
## Project Structure
133+
134+
Key files to understand:
135+
136+
- `cli/src/commands/create-expo-stack.ts`: Main CLI command logic
137+
- `cli/src/utilities/configureProjectFiles.ts`: File configuration logic
138+
- `cli/src/utilities/generateProjectFiles.ts`: Project generation logic
139+
- `cli/src/types.ts`: TypeScript types for CLI options

cli/src/templates/packages/react-navigation/App.tsx.ejs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<% } %>
77
<% if (props.stylingPackage?.name === "unistyles") { %>
88
import './unistyles';
9+
import { DefaultTheme } from '@react-navigation/native';
10+
import { useUnistyles } from 'react-native-unistyles';
911
<% } %>
1012
<% if (props.internalizationPackage?.name === "i18next") { %>
1113
import './translation';
@@ -63,6 +65,24 @@ export default function App() {
6365
<RootStack />
6466
</ThemeProvider>
6567
);
68+
<% } else if (props.stylingPackage?.name === "unistyles") { %>
69+
const { theme, rt } = useUnistyles();
70+
71+
const mergedTheme = {
72+
...DefaultTheme,
73+
colors: {
74+
background: theme.colors.background,
75+
text: theme.colors.typography,
76+
primary: theme.colors.astral,
77+
secondary: theme.colors.cornflowerBlue,
78+
border: theme.colors.limedSpruce,
79+
card: theme.colors.background,
80+
notification: theme.colors.astral,
81+
},
82+
dark: rt.colorScheme === 'dark',
83+
};
84+
85+
return <RootStack theme={mergedTheme} />;
6686
<% } else { %>
6787
return <RootStack />;
6888
<% } %>

cli/src/templates/packages/react-navigation/navigation/drawer-navigator.tsx.ejs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,11 @@
11
import { Ionicons, MaterialIcons } from '@expo/vector-icons';
22
import { createDrawerNavigator } from '@react-navigation/drawer';
33
import { HeaderButton } from 'components/HeaderButton';
4-
<% if (props.stylingPackage?.name === "unistyles") { %>
5-
import { StyleSheet } from 'react-native-unistyles';
6-
<% } %>
7-
84
import TabNavigator from './tab-navigator';
95
import Home from '../screens/home';
106

11-
<% if (props.stylingPackage?.name === "unistyles") { %>
12-
const stylesheet = StyleSheet.create((theme) => ({
13-
headerStyle: {
14-
backgroundColor: theme.colors.background,
15-
},
16-
headerTitleStyle: {
17-
color: theme.colors.typography,
18-
},
19-
headerTintColor: {
20-
color: theme.colors.typography
21-
},
22-
drawerStyle: {
23-
backgroundColor: theme.colors.background,
24-
},
25-
drawerLabelStyle: {
26-
color: theme.colors.typography,
27-
},
28-
drawerInactiveTintColor: {
29-
color: theme.colors.typography
30-
},
31-
}))
32-
<% } %>
337

348
const Drawer = createDrawerNavigator({
35-
<% if (props.stylingPackage?.name === "unistyles") { %>
36-
screenOptions: {
37-
headerStyle: { backgroundColor: stylesheet.headerStyle.backgroundColor },
38-
headerTitleStyle: stylesheet.headerTitleStyle,
39-
headerTintColor: stylesheet.headerTintColor.color,
40-
drawerStyle: stylesheet.drawerStyle,
41-
drawerLabelStyle: stylesheet.drawerLabelStyle,
42-
drawerInactiveTintColor: stylesheet.drawerInactiveTintColor.color,
43-
},
44-
<% } %>
459
screens: {
4610
Home: {
4711
screen: Home,

cli/src/templates/packages/react-navigation/navigation/index.tsx.ejs

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,11 @@
11
<% if (props.navigationPackage?.options.type === 'stack') { %>
22
import { createStaticNavigation, StaticParamList } from '@react-navigation/native';
33
import { createStackNavigator } from '@react-navigation/stack';
4-
5-
<% if (props.stylingPackage?.name === "unistyles") { %>
6-
import { StyleSheet } from 'react-native-unistyles';
7-
<% } %>
8-
94
import Overview from "../screens/overview";
105
import Details from "../screens/details";
116
import { BackButton } from '../components/BackButton';
127
13-
<% if (props.stylingPackage?.name === "unistyles") { %>
14-
const stylesheet = StyleSheet.create((theme) => ({
15-
headerStyle: {
16-
backgroundColor: theme.colors.background,
17-
},
18-
headerTitleStyle: {
19-
color: theme.colors.typography,
20-
},
21-
headerTintColor: {
22-
color: theme.colors.typography
23-
},
24-
}))
25-
<% } %>
26-
278
const Stack = createStackNavigator({
28-
<% if (props.stylingPackage?.name === "unistyles") { %>
29-
screenOptions: {
30-
headerStyle: { backgroundColor: stylesheet.headerStyle.backgroundColor },
31-
headerTitleStyle: stylesheet.headerTitleStyle,
32-
headerTintColor: stylesheet.headerTintColor.color,
33-
},
34-
<% } %>
359
screens: {
3610
Overview: {
3711
screen: Overview,
@@ -59,35 +33,11 @@
5933
<% } else if (props.navigationPackage?.options.type === 'tabs') { %>
6034
import { createStaticNavigation, StaticParamList } from '@react-navigation/native';
6135
import { createStackNavigator } from "@react-navigation/stack";
62-
<% if (props.stylingPackage?.name === "unistyles") { %>
63-
import { StyleSheet } from 'react-native-unistyles';
64-
<% } %>
65-
6636
import Modal from "../screens/modal";
6737
import TabNavigator from "./tab-navigator";
6838
69-
<% if (props.stylingPackage?.name === "unistyles") { %>
70-
const stylesheet = StyleSheet.create((theme) => ({
71-
headerStyle: {
72-
backgroundColor: theme.colors.background,
73-
},
74-
headerTitleStyle: {
75-
color: theme.colors.typography,
76-
},
77-
headerTintColor: {
78-
color: theme.colors.typography
79-
},
80-
}))
81-
<% } %>
8239
8340
const Stack = createStackNavigator({
84-
<% if (props.stylingPackage?.name === "unistyles") { %>
85-
screenOptions: {
86-
headerStyle: { backgroundColor: stylesheet.headerStyle.backgroundColor },
87-
headerTitleStyle: stylesheet.headerTitleStyle,
88-
headerTintColor: stylesheet.headerTintColor.color,
89-
},
90-
<% } %>
9141
screens: {
9242
TabNavigator: {
9343
screen: TabNavigator,
@@ -119,36 +69,11 @@
11969
<% } else if (props.navigationPackage?.options.type === 'drawer + tabs') { %>
12070
import { createStaticNavigation, StaticParamList } from '@react-navigation/native';
12171
import { createStackNavigator } from '@react-navigation/stack';
122-
<% if (props.stylingPackage?.name === "unistyles") { %>
123-
import { StyleSheet } from 'react-native-unistyles';
124-
<% } %>
125-
12672
import Modal from "../screens/modal";
12773
import DrawerNavigator from "./drawer-navigator";
12874
129-
<% if (props.stylingPackage?.name === "unistyles") { %>
130-
const stylesheet = StyleSheet.create((theme) => ({
131-
headerStyle: {
132-
backgroundColor: theme.colors.background,
133-
},
134-
headerTitleStyle: {
135-
color: theme.colors.typography,
136-
},
137-
headerTintColor: {
138-
color: theme.colors.typography
139-
},
140-
}))
141-
<% } %>
142-
14375
14476
const Stack = createStackNavigator({
145-
<% if (props.stylingPackage?.name === "unistyles") { %>
146-
screenOptions: {
147-
headerStyle: { backgroundColor: stylesheet.headerStyle.backgroundColor },
148-
headerTitleStyle: stylesheet.headerTitleStyle,
149-
headerTintColor: stylesheet.headerTintColor.color,
150-
},
151-
<% } %>
15277
screens: {
15378
DrawerNavigator: {
15479
screen: DrawerNavigator,

cli/src/templates/packages/react-navigation/navigation/tab-navigator.tsx.ejs

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,19 @@
11
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
2-
<% if (props.stylingPackage?.name === "unistyles") { %>
3-
import { StyleSheet } from 'react-native-unistyles';
4-
<% } %>
52
import { HeaderButton } from '../components/HeaderButton';
63
import { TabBarIcon } from '../components/TabBarIcon';
74
import One from '../screens/one';
85
import Two from '../screens/two';
96

10-
<% if (props.stylingPackage?.name === "unistyles") { %>
11-
const stylesheet = StyleSheet.create((theme) => ({
12-
headerStyle: {
13-
backgroundColor: theme.colors.background,
14-
},
15-
headerTitleStyle: {
16-
color: theme.colors.typography,
17-
},
18-
tabBarActiveTintColor: {color: theme.colors.astral},
19-
tabBarStyle: {
20-
backgroundColor: theme.colors.background,
21-
},
22-
}))
23-
<% } %>
24-
257
const Tab = createBottomTabNavigator({
26-
screenOptions: {
27-
<% if (props.stylingPackage?.name === "unistyles") { %>
28-
headerStyle: { backgroundColor: stylesheet.headerStyle.backgroundColor },
29-
headerTitleStyle: stylesheet.headerTitleStyle,
30-
tabBarActiveTintColor: stylesheet.tabBarActiveTintColor.color,
31-
tabBarStyle: stylesheet.tabBarStyle,
32-
<% } else { %>
33-
tabBarActiveTintColor: 'black',
34-
<% } %>
35-
<% if (props.navigationPackage?.options.type === 'drawer + tabs') { %>
36-
headerShown: false,
37-
<% } %>
8+
screenOptions: function ScreenOptions() {
9+
return {
10+
<% if (props.stylingPackage?.name !== "unistyles") { %>
11+
tabBarActiveTintColor: 'black',
12+
<% } %>
13+
<% if (props.navigationPackage?.options.type === 'drawer + tabs') { %>
14+
headerShown: false,
15+
<% } %>
16+
}
3817
},
3918
screens: {
4019
One: {

0 commit comments

Comments
 (0)