@exanderal/stackcraft 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +14 -3
  2. package/dist/create/index.d.ts.map +1 -1
  3. package/dist/create/index.js +12 -0
  4. package/dist/create/index.js.map +1 -1
  5. package/dist/create/scaffold.d.ts.map +1 -1
  6. package/dist/create/scaffold.js +5 -0
  7. package/dist/create/scaffold.js.map +1 -1
  8. package/dist/create/scaffolders/__tests__/web-vite.test.js +1 -0
  9. package/dist/create/scaffolders/__tests__/web-vite.test.js.map +1 -1
  10. package/dist/create/scaffolders/mobile-expo.d.ts +3 -0
  11. package/dist/create/scaffolders/mobile-expo.d.ts.map +1 -0
  12. package/dist/create/scaffolders/mobile-expo.js +14 -0
  13. package/dist/create/scaffolders/mobile-expo.js.map +1 -0
  14. package/dist/create/scaffolders/wire-client.d.ts.map +1 -1
  15. package/dist/create/scaffolders/wire-client.js +14 -0
  16. package/dist/create/scaffolders/wire-client.js.map +1 -1
  17. package/dist/create/types.d.ts +2 -0
  18. package/dist/create/types.d.ts.map +1 -1
  19. package/package.json +1 -1
  20. package/templates/base/tools/generators/module/schema.json +2 -1
  21. package/templates/mobile-expo/app/(tabs)/_layout.tsx +31 -0
  22. package/templates/mobile-expo/app/(tabs)/index.tsx +23 -0
  23. package/templates/mobile-expo/app/+not-found.tsx +40 -0
  24. package/templates/mobile-expo/app/_layout.tsx +31 -0
  25. package/templates/mobile-expo/app.json +39 -0
  26. package/templates/mobile-expo/assets/images/adaptive-icon.png +0 -0
  27. package/templates/mobile-expo/assets/images/favicon.png +0 -0
  28. package/templates/mobile-expo/assets/images/icon.png +0 -0
  29. package/templates/mobile-expo/assets/images/splash-icon.png +0 -0
  30. package/templates/mobile-expo/components/ExternalLink.tsx +25 -0
  31. package/templates/mobile-expo/components/StyledText.tsx +5 -0
  32. package/templates/mobile-expo/components/Themed.tsx +45 -0
  33. package/templates/mobile-expo/components/useClientOnlyValue.ts +4 -0
  34. package/templates/mobile-expo/components/useClientOnlyValue.web.ts +12 -0
  35. package/templates/mobile-expo/components/useColorScheme.ts +1 -0
  36. package/templates/mobile-expo/components/useColorScheme.web.ts +8 -0
  37. package/templates/mobile-expo/constants/Colors.ts +19 -0
  38. package/templates/mobile-expo/package.json +37 -0
  39. package/templates/mobile-expo/project.json +17 -0
  40. package/templates/mobile-expo/tsconfig.json +20 -0
package/README.md CHANGED
@@ -18,7 +18,8 @@ Follow the prompts — you'll have an Nx monorepo with deps installed and ready
18
18
  your-project/
19
19
  ├── apps/
20
20
  │ ├── backend/ # NestJS REST or GraphQL API
21
- └── web/ # Vite + React or Next.js
21
+ ├── web/ # Vite + React or Next.js
22
+ │ └── mobile/ # Expo (optional)
22
23
  ├── packages/
23
24
  │ └── types/ # auto-generated types shared across all apps
24
25
  └── tools/
@@ -51,6 +52,13 @@ src/
51
52
  - TypeScript
52
53
  - GraphQL projects: Apollo Client pre-configured, `ApolloProvider` already wired at the app root
53
54
 
55
+ ### Mobile (`apps/mobile`) — optional
56
+
57
+ - Expo with Expo Router (file-based navigation)
58
+ - React Native
59
+ - `@local/types` already wired — import shared types directly
60
+ - GraphQL projects: Apollo Client added automatically
61
+
54
62
  ### Types (`packages/types`)
55
63
 
56
64
  Auto-generated TypeScript types shared across all apps — import from `@local/types/rest` or `@local/types/graphql`:
@@ -88,9 +96,10 @@ Generate a new domain module (model + repository + service):
88
96
 
89
97
  ```sh
90
98
  pnpm generate:module --name=trainer
91
- pnpm generate:module --name=trainer --graphql # adds @ObjectType() to the model
92
99
  ```
93
100
 
101
+ You'll be prompted whether to add `@ObjectType()` to the model (required for GraphQL resolvers). Pass `--graphql` to skip the prompt.
102
+
94
103
  Generate a REST controller:
95
104
 
96
105
  ```sh
@@ -137,6 +146,7 @@ const { data, loading } = useGetTrainersQuery()
137
146
  | Backend | NestJS, TypeORM |
138
147
  | Database | PostgreSQL or MySQL |
139
148
  | Frontend | Vite + React or Next.js |
149
+ | Mobile | Expo + Expo Router |
140
150
  | Styles | Tailwind CSS v4 |
141
151
  | GraphQL client | Apollo Client |
142
152
  | REST types | @hey-api/openapi-ts |
@@ -151,7 +161,8 @@ const { data, loading } = useGetTrainersQuery()
151
161
  - [x] `codegen:watch` for live type generation during dev
152
162
  - [x] Apollo Client pre-configured in GraphQL projects
153
163
  - [x] Typed Apollo hooks from `.graphql` operation files
154
- - [ ] Expo mobile
164
+ - [x] Expo mobile with Expo Router
165
+ - [x] Interactive `generate:module` prompt
155
166
  - [ ] `stackcraft add` addon system (auth, Supabase, etc.)
156
167
  - [ ] Presets and `--config` for non-interactive use
157
168
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,kBA4E3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,kBAyF3B"}
@@ -34,6 +34,17 @@ export async function create() {
34
34
  cancel('Cancelled.');
35
35
  process.exit(0);
36
36
  }
37
+ const mobile = await select({
38
+ message: 'Mobile',
39
+ options: [
40
+ { value: 'none', label: 'None' },
41
+ { value: 'expo', label: 'Expo', hint: 'React Native with Expo Router' },
42
+ ],
43
+ });
44
+ if (isCancel(mobile)) {
45
+ cancel('Cancelled.');
46
+ process.exit(0);
47
+ }
37
48
  const database = await select({
38
49
  message: 'Database',
39
50
  options: [
@@ -61,6 +72,7 @@ export async function create() {
61
72
  frontend: frontend,
62
73
  backend: backend,
63
74
  database: database,
75
+ mobile: mobile,
64
76
  packageManager: packageManager,
65
77
  targetDir: resolve(process.cwd(), projectName),
66
78
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAsB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,iBAwBlF"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAsB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,iBA6BlF"}
@@ -2,6 +2,7 @@ import { execa } from 'execa';
2
2
  import { scaffoldNestjsGraphql } from './scaffolders/api-nestjs-graphql.js';
3
3
  import { scaffoldNestjsRest } from './scaffolders/api-nestjs-rest.js';
4
4
  import { scaffoldBase } from './scaffolders/base.js';
5
+ import { scaffoldExpo } from './scaffolders/mobile-expo.js';
5
6
  import { scaffoldNextjs } from './scaffolders/web-nextjs.js';
6
7
  import { scaffoldVite } from './scaffolders/web-vite.js';
7
8
  import { wireClientIntegration } from './scaffolders/wire-client.js';
@@ -23,6 +24,10 @@ export async function scaffold(config, onStep) {
23
24
  onStep('Adding Next.js app...');
24
25
  await scaffoldNextjs(config);
25
26
  }
27
+ if (config.mobile === 'expo') {
28
+ onStep('Adding Expo mobile app...');
29
+ await scaffoldExpo(config);
30
+ }
26
31
  onStep('Wiring client integration...');
27
32
  await wireClientIntegration(config);
28
33
  onStep('Installing dependencies...');
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAGpE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAqB,EAAE,MAA6B;IACjF,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAC/B,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAE1B,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC3B,IAAI,MAAM,CAAC,OAAO,KAAK,gBAAgB,EAAE,CAAC;QACxC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAA;IACrC,CAAC;SAAM,CAAC;QACN,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,4BAA4B,CAAC,CAAA;QACpC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,CAAC,uBAAuB,CAAC,CAAA;QAC/B,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,8BAA8B,CAAC,CAAA;IACtC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAA;IAEnC,MAAM,CAAC,4BAA4B,CAAC,CAAA;IACpC,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;AAC5E,CAAC"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/create/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAGpE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAqB,EAAE,MAA6B;IACjF,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAC/B,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAE1B,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC3B,IAAI,MAAM,CAAC,OAAO,KAAK,gBAAgB,EAAE,CAAC;QACxC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAA;IACrC,CAAC;SAAM,CAAC;QACN,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,4BAA4B,CAAC,CAAA;QACpC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,CAAC;SAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,CAAC,uBAAuB,CAAC,CAAA;QAC/B,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,CAAC,2BAA2B,CAAC,CAAA;QACnC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,CAAC;IAED,MAAM,CAAC,8BAA8B,CAAC,CAAA;IACtC,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAA;IAEnC,MAAM,CAAC,4BAA4B,CAAC,CAAA;IACpC,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;AAC5E,CAAC"}
@@ -11,6 +11,7 @@ const CONFIG = {
11
11
  frontend: 'vite',
12
12
  backend: 'nestjs-rest',
13
13
  database: 'postgres',
14
+ mobile: 'none',
14
15
  packageManager: 'pnpm',
15
16
  targetDir: '/tmp/my-app',
16
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"web-vite.test.js","sourceRoot":"","sources":["../../../../src/create/scaffolders/__tests__/web-vite.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE5D,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IAC3C,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IACxC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACtC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACvC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;CAChD,CAAC,CAAC,CAAA;AAEH,MAAM,MAAM,GAAG;IACb,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE,aAAsB;IAC/B,QAAQ,EAAE,UAAmB;IAC7B,cAAc,EAAE,MAAe;IAC/B,SAAS,EAAE,aAAa;CACzB,CAAA;AAED,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAA;IAEnC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAChC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAC/C,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAC7B,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"web-vite.test.js","sourceRoot":"","sources":["../../../../src/create/scaffolders/__tests__/web-vite.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE5D,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IAC3C,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IACxC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACtC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACvC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;CAChD,CAAC,CAAC,CAAA;AAEH,MAAM,MAAM,GAAG;IACb,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE,aAAsB;IAC/B,QAAQ,EAAE,UAAmB;IAC7B,MAAM,EAAE,MAAe;IACvB,cAAc,EAAE,MAAe;IAC/B,SAAS,EAAE,aAAa;CACzB,CAAA;AAED,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAA;IAEnC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAChC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAC/C,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QAE1B,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAC7B,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACnC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectConfig } from '../types.js';
2
+ export declare function scaffoldExpo(config: ProjectConfig): Promise<void>;
3
+ //# sourceMappingURL=mobile-expo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-expo.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/mobile-expo.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,iBAOvD"}
@@ -0,0 +1,14 @@
1
+ import { mkdir } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { copyTemplate } from './utils/copy.js';
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const TEMPLATES_DIR = join(__dirname, '..', '..', '..', 'templates');
7
+ export async function scaffoldExpo(config) {
8
+ const appDir = join(config.targetDir, 'apps', 'mobile');
9
+ await mkdir(appDir, { recursive: true });
10
+ await copyTemplate(join(TEMPLATES_DIR, 'mobile-expo'), appDir, {
11
+ projectName: config.projectName,
12
+ });
13
+ }
14
+ //# sourceMappingURL=mobile-expo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-expo.js","sourceRoot":"","sources":["../../../src/create/scaffolders/mobile-expo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAA;AAEpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAqB;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;IACvD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAExC,MAAM,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE;QAC7D,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAA;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"wire-client.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/wire-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,aAAa,iBAehE"}
1
+ {"version":3,"file":"wire-client.d.ts","sourceRoot":"","sources":["../../../src/create/scaffolders/wire-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,aAAa,iBAmBhE"}
@@ -14,6 +14,20 @@ export async function wireClientIntegration(config) {
14
14
  else {
15
15
  await writeFile(webPkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
16
16
  }
17
+ if (config.mobile === 'expo') {
18
+ await wireMobileTypes(config);
19
+ }
20
+ }
21
+ async function wireMobileTypes(config) {
22
+ const mobileDir = join(config.targetDir, 'apps', 'mobile');
23
+ const mobilePkgPath = join(mobileDir, 'package.json');
24
+ const pkg = JSON.parse(await readFile(mobilePkgPath, 'utf-8'));
25
+ pkg.dependencies['@local/types'] = 'workspace:*';
26
+ if (config.backend === 'nestjs-graphql') {
27
+ pkg.dependencies['@apollo/client'] = '^3.13.0';
28
+ pkg.dependencies['graphql'] = '^16.0.0';
29
+ }
30
+ await writeFile(mobilePkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
17
31
  }
18
32
  async function setupApolloClient(config, webDir) {
19
33
  await mkdir(join(webDir, 'src', 'lib'), { recursive: true });
@@ -1 +1 @@
1
- {"version":3,"file":"wire-client.js","sourceRoot":"","sources":["../../../src/create/scaffolders/wire-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wire-client.js","sourceRoot":"","sources":["../../../src/create/scaffolders/wire-client.ts"],"names":[],"mappings":"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"}
@@ -2,11 +2,13 @@ export type PackageManager = 'pnpm' | 'npm';
2
2
  export type Frontend = 'vite' | 'nextjs';
3
3
  export type Backend = 'nestjs-rest' | 'nestjs-graphql';
4
4
  export type Database = 'postgres' | 'mysql';
5
+ export type Mobile = 'expo' | 'none';
5
6
  export interface ProjectConfig {
6
7
  projectName: string;
7
8
  frontend: Frontend;
8
9
  backend: Backend;
9
10
  database: Database;
11
+ mobile: Mobile;
10
12
  packageManager: PackageManager;
11
13
  targetDir: string;
12
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/create/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAA;AAC3C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AACxC,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,gBAAgB,CAAA;AACtD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAE3C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;CAClB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/create/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAA;AAC3C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AACxC,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,gBAAgB,CAAA;AACtD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAC3C,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;AAEpC,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;CAClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exanderal/stackcraft",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Opinionated full-stack project scaffolding CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,8 @@
16
16
  "graphql": {
17
17
  "type": "boolean",
18
18
  "description": "Add @ObjectType() to the model (required for GraphQL resolvers)",
19
- "default": false
19
+ "default": false,
20
+ "x-prompt": "Add @ObjectType() to the model? (required for GraphQL resolvers)"
20
21
  }
21
22
  },
22
23
  "required": ["name"]
@@ -0,0 +1,31 @@
1
+ import FontAwesome from '@expo/vector-icons/FontAwesome';
2
+ import { Tabs } from 'expo-router';
3
+
4
+ import Colors from '@/constants/Colors';
5
+ import { useColorScheme } from '@/components/useColorScheme';
6
+
7
+ function TabBarIcon(props: {
8
+ name: React.ComponentProps<typeof FontAwesome>['name'];
9
+ color: string;
10
+ }) {
11
+ return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
12
+ }
13
+
14
+ export default function TabLayout() {
15
+ const colorScheme = useColorScheme();
16
+
17
+ return (
18
+ <Tabs
19
+ screenOptions={{
20
+ tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
21
+ }}>
22
+ <Tabs.Screen
23
+ name="index"
24
+ options={{
25
+ title: 'Home',
26
+ tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
27
+ }}
28
+ />
29
+ </Tabs>
30
+ );
31
+ }
@@ -0,0 +1,23 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { Text, View } from '@/components/Themed';
4
+
5
+ export default function HomeScreen() {
6
+ return (
7
+ <View style={styles.container}>
8
+ <Text style={styles.title}>Home</Text>
9
+ </View>
10
+ );
11
+ }
12
+
13
+ const styles = StyleSheet.create({
14
+ container: {
15
+ flex: 1,
16
+ alignItems: 'center',
17
+ justifyContent: 'center',
18
+ },
19
+ title: {
20
+ fontSize: 20,
21
+ fontWeight: 'bold',
22
+ },
23
+ });
@@ -0,0 +1,40 @@
1
+ import { Link, Stack } from 'expo-router';
2
+ import { StyleSheet } from 'react-native';
3
+
4
+ import { Text, View } from '@/components/Themed';
5
+
6
+ export default function NotFoundScreen() {
7
+ return (
8
+ <>
9
+ <Stack.Screen options={{ title: 'Oops!' }} />
10
+ <View style={styles.container}>
11
+ <Text style={styles.title}>This screen doesn't exist.</Text>
12
+
13
+ <Link href="/" style={styles.link}>
14
+ <Text style={styles.linkText}>Go to home screen!</Text>
15
+ </Link>
16
+ </View>
17
+ </>
18
+ );
19
+ }
20
+
21
+ const styles = StyleSheet.create({
22
+ container: {
23
+ flex: 1,
24
+ alignItems: 'center',
25
+ justifyContent: 'center',
26
+ padding: 20,
27
+ },
28
+ title: {
29
+ fontSize: 20,
30
+ fontWeight: 'bold',
31
+ },
32
+ link: {
33
+ marginTop: 15,
34
+ paddingVertical: 15,
35
+ },
36
+ linkText: {
37
+ fontSize: 14,
38
+ color: '#2e78b7',
39
+ },
40
+ });
@@ -0,0 +1,31 @@
1
+ import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
2
+ import { Stack } from 'expo-router';
3
+ import * as SplashScreen from 'expo-splash-screen';
4
+ import { useEffect } from 'react';
5
+ import 'react-native-reanimated';
6
+
7
+ import { useColorScheme } from '@/components/useColorScheme';
8
+
9
+ export { ErrorBoundary } from 'expo-router';
10
+
11
+ export const unstable_settings = {
12
+ initialRouteName: '(tabs)',
13
+ };
14
+
15
+ SplashScreen.preventAutoHideAsync();
16
+
17
+ export default function RootLayout() {
18
+ const colorScheme = useColorScheme();
19
+
20
+ useEffect(() => {
21
+ SplashScreen.hideAsync();
22
+ }, []);
23
+
24
+ return (
25
+ <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
26
+ <Stack>
27
+ <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
28
+ </Stack>
29
+ </ThemeProvider>
30
+ );
31
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "expo": {
3
+ "name": "{{projectName}}",
4
+ "slug": "{{projectName}}",
5
+ "version": "1.0.0",
6
+ "orientation": "portrait",
7
+ "icon": "./assets/images/icon.png",
8
+ "scheme": "{{projectName}}",
9
+ "userInterfaceStyle": "automatic",
10
+ "newArchEnabled": true,
11
+ "splash": {
12
+ "image": "./assets/images/splash-icon.png",
13
+ "resizeMode": "contain",
14
+ "backgroundColor": "#ffffff"
15
+ },
16
+ "ios": {
17
+ "supportsTablet": true
18
+ },
19
+ "android": {
20
+ "adaptiveIcon": {
21
+ "foregroundImage": "./assets/images/adaptive-icon.png",
22
+ "backgroundColor": "#ffffff"
23
+ },
24
+ "edgeToEdgeEnabled": true,
25
+ "predictiveBackGestureEnabled": false
26
+ },
27
+ "web": {
28
+ "bundler": "metro",
29
+ "output": "static",
30
+ "favicon": "./assets/images/favicon.png"
31
+ },
32
+ "plugins": [
33
+ "expo-router"
34
+ ],
35
+ "experiments": {
36
+ "typedRoutes": true
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,25 @@
1
+ import { Link } from 'expo-router';
2
+ import * as WebBrowser from 'expo-web-browser';
3
+ import React from 'react';
4
+ import { Platform } from 'react-native';
5
+
6
+ export function ExternalLink(
7
+ props: Omit<React.ComponentProps<typeof Link>, 'href'> & { href: string }
8
+ ) {
9
+ return (
10
+ <Link
11
+ target="_blank"
12
+ {...props}
13
+ // @ts-expect-error: External URLs are not typed.
14
+ href={props.href}
15
+ onPress={(e) => {
16
+ if (Platform.OS !== 'web') {
17
+ // Prevent the default behavior of linking to the default browser on native.
18
+ e.preventDefault();
19
+ // Open the link in an in-app browser.
20
+ WebBrowser.openBrowserAsync(props.href as string);
21
+ }
22
+ }}
23
+ />
24
+ );
25
+ }
@@ -0,0 +1,5 @@
1
+ import { Text, TextProps } from './Themed';
2
+
3
+ export function MonoText(props: TextProps) {
4
+ return <Text {...props} style={[props.style, { fontFamily: 'SpaceMono' }]} />;
5
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Learn more about Light and Dark modes:
3
+ * https://docs.expo.io/guides/color-schemes/
4
+ */
5
+
6
+ import { Text as DefaultText, View as DefaultView } from 'react-native';
7
+
8
+ import Colors from '@/constants/Colors';
9
+ import { useColorScheme } from './useColorScheme';
10
+
11
+ type ThemeProps = {
12
+ lightColor?: string;
13
+ darkColor?: string;
14
+ };
15
+
16
+ export type TextProps = ThemeProps & DefaultText['props'];
17
+ export type ViewProps = ThemeProps & DefaultView['props'];
18
+
19
+ export function useThemeColor(
20
+ props: { light?: string; dark?: string },
21
+ colorName: keyof typeof Colors.light & keyof typeof Colors.dark
22
+ ) {
23
+ const theme = useColorScheme() ?? 'light';
24
+ const colorFromProps = props[theme];
25
+
26
+ if (colorFromProps) {
27
+ return colorFromProps;
28
+ } else {
29
+ return Colors[theme][colorName];
30
+ }
31
+ }
32
+
33
+ export function Text(props: TextProps) {
34
+ const { style, lightColor, darkColor, ...otherProps } = props;
35
+ const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
36
+
37
+ return <DefaultText style={[{ color }, style]} {...otherProps} />;
38
+ }
39
+
40
+ export function View(props: ViewProps) {
41
+ const { style, lightColor, darkColor, ...otherProps } = props;
42
+ const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
43
+
44
+ return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
45
+ }
@@ -0,0 +1,4 @@
1
+ // This function is web-only as native doesn't currently support server (or build-time) rendering.
2
+ export function useClientOnlyValue<S, C>(server: S, client: C): S | C {
3
+ return client;
4
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+
3
+ // `useEffect` is not invoked during server rendering, meaning
4
+ // we can use this to determine if we're on the server or not.
5
+ export function useClientOnlyValue<S, C>(server: S, client: C): S | C {
6
+ const [value, setValue] = React.useState<S | C>(server);
7
+ React.useEffect(() => {
8
+ setValue(client);
9
+ }, [client]);
10
+
11
+ return value;
12
+ }
@@ -0,0 +1 @@
1
+ export { useColorScheme } from 'react-native';
@@ -0,0 +1,8 @@
1
+ // NOTE: The default React Native styling doesn't support server rendering.
2
+ // Server rendered styles should not change between the first render of the HTML
3
+ // and the first render on the client. Typically, web developers will use CSS media queries
4
+ // to render different styles on the client and server, these aren't directly supported in React Native
5
+ // but can be achieved using a styling library like Nativewind.
6
+ export function useColorScheme() {
7
+ return 'light';
8
+ }
@@ -0,0 +1,19 @@
1
+ const tintColorLight = '#2f95dc';
2
+ const tintColorDark = '#fff';
3
+
4
+ export default {
5
+ light: {
6
+ text: '#000',
7
+ background: '#fff',
8
+ tint: tintColorLight,
9
+ tabIconDefault: '#ccc',
10
+ tabIconSelected: tintColorLight,
11
+ },
12
+ dark: {
13
+ text: '#fff',
14
+ background: '#000',
15
+ tint: tintColorDark,
16
+ tabIconDefault: '#ccc',
17
+ tabIconSelected: tintColorDark,
18
+ },
19
+ };
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "{{projectName}}-mobile",
3
+ "main": "expo-router/entry",
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "dev": "expo start",
7
+ "android": "expo start --android",
8
+ "ios": "expo start --ios",
9
+ "web": "expo start --web",
10
+ "build": "expo export"
11
+ },
12
+ "dependencies": {
13
+ "@expo/vector-icons": "^15.0.3",
14
+ "@react-navigation/native": "^7.1.8",
15
+ "expo": "~54.0.33",
16
+ "expo-constants": "~18.0.13",
17
+ "expo-font": "~14.0.11",
18
+ "expo-linking": "~8.0.11",
19
+ "expo-router": "~6.0.23",
20
+ "expo-splash-screen": "~31.0.13",
21
+ "expo-status-bar": "~3.0.9",
22
+ "expo-web-browser": "~15.0.10",
23
+ "react": "19.1.0",
24
+ "react-dom": "19.1.0",
25
+ "react-native": "0.81.5",
26
+ "react-native-worklets": "0.5.1",
27
+ "react-native-reanimated": "~4.1.1",
28
+ "react-native-safe-area-context": "~5.6.0",
29
+ "react-native-screens": "~4.16.0",
30
+ "react-native-web": "~0.21.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "~19.1.0",
34
+ "typescript": "~5.9.2"
35
+ },
36
+ "private": true
37
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "mobile",
3
+ "targets": {
4
+ "dev": {
5
+ "executor": "nx:run-commands",
6
+ "options": { "command": "pnpm run dev", "cwd": "{projectRoot}" }
7
+ },
8
+ "build": {
9
+ "executor": "nx:run-commands",
10
+ "options": { "command": "pnpm run build", "cwd": "{projectRoot}" }
11
+ },
12
+ "lint": {
13
+ "executor": "nx:run-commands",
14
+ "options": { "command": "pnpm run lint", "cwd": "{projectRoot}" }
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "paths": {
6
+ "@/*": [
7
+ "./*"
8
+ ],
9
+ "@local/types/*": [
10
+ "../../packages/types/src/*"
11
+ ]
12
+ }
13
+ },
14
+ "include": [
15
+ "**/*.ts",
16
+ "**/*.tsx",
17
+ ".expo/types/**/*.ts",
18
+ "expo-env.d.ts"
19
+ ]
20
+ }