diff --git a/index.ts b/index.ts
index 1638481..fd5e3c9 100644
--- a/index.ts
+++ b/index.ts
@@ -18,13 +18,22 @@ const project = await p.group(
return undefined
},
}),
- frontend: async () =>
+ frontend: async () =>
await p.select({
message: 'Pick a frontend framework.',
options: [
- {value: "svelte-kit", label:"SvelteKit"},
- {value: "solid-start", label:"SolidStart"},
- {value: "none", label:"None"}
+ { value: "svelte-kit", label: "SvelteKit" },
+ { value: "solid-start", label: "SolidStart" },
+ { value: "none", label: "None" }
+ ]
+ })
+ ,
+ mobile: async () =>
+ await p.select({
+ message: 'Pick a mobile framework.',
+ options: [
+ { value: "expo", label: "ReactNative + Expo" },
+ { value: "none", label: "None" }
]
})
,
@@ -55,15 +64,18 @@ const render = createRenderer(z.object({
frontend: z.string(),
})
}))
-const destDir = path.join("./",project.name);
-render(destDir,{project},{reverseMap: true})
+const destDir = path.join("./", project.name);
+render(destDir, { project }, { reverseMap: true })
const s = p.spinner();
s.start("Installing dependencies");
await Bun.$`bun install`.cwd(path.join(destDir)).quiet();
-await Bun.$`bun install`.cwd(path.join(destDir,'packages','rpc')).quiet();
+await Bun.$`bun install`.cwd(path.join(destDir, 'packages', 'rpc')).quiet();
if (project.frontend !== "none") {
- await Bun.$`bun install`.cwd(path.join(destDir,'apps','web')).quiet();
+ await Bun.$`bun install`.cwd(path.join(destDir, 'apps', 'web')).quiet();
+}
+if (project.mobile !== "none") {
+ await Bun.$`bun install`.cwd(path.join(destDir, 'apps', 'mobile')).quiet();
}
s.stop("Dependencies installed.");
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.claude/settings.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.claude/settings.json"
new file mode 100644
index 0000000..176e6a5
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.claude/settings.json"
@@ -0,0 +1,5 @@
+{
+ "enabledPlugins": {
+ "expo@claude-plugins-official": true
+ }
+}
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.gitignore" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.gitignore"
new file mode 100644
index 0000000..4b00baf
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.gitignore"
@@ -0,0 +1,43 @@
+# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
+
+# dependencies
+node_modules/
+
+# Expo
+.expo/
+dist/
+web-build/
+expo-env.d.ts
+
+# Native
+.kotlin/
+*.orig.*
+*.jks
+*.p8
+*.p12
+*.key
+*.mobileprovision
+
+# Metro
+.metro-health-check*
+
+# debug
+npm-debug.*
+yarn-debug.*
+yarn-error.*
+
+# macOS
+.DS_Store
+*.pem
+
+# local env files
+.env*.local
+
+# typescript
+*.tsbuildinfo
+
+example
+
+# generated native folders
+/ios
+/android
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.ignore" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.ignore"
new file mode 100644
index 0000000..52e5644
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.ignore"
@@ -0,0 +1,4 @@
+.expo
+android
+node_modules
+assets
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.vscode/extensions.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.vscode/extensions.json"
new file mode 100644
index 0000000..b7ed837
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.vscode/extensions.json"
@@ -0,0 +1 @@
+{ "recommendations": ["expo.vscode-expo-tools"] }
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.vscode/settings.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.vscode/settings.json"
new file mode 100644
index 0000000..e2798e4
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/.vscode/settings.json"
@@ -0,0 +1,7 @@
+{
+ "editor.codeActionsOnSave": {
+ "source.fixAll": "explicit",
+ "source.organizeImports": "explicit",
+ "source.sortMembers": "explicit"
+ }
+}
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/AGENTS.md" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/AGENTS.md"
new file mode 100644
index 0000000..a26b4bb
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/AGENTS.md"
@@ -0,0 +1,3 @@
+# Expo HAS CHANGED
+
+Read the exact versioned docs at https://docs.expo.dev/versions/v56.0.0/ before writing any code.
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/CLAUDE.md" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/CLAUDE.md"
new file mode 100644
index 0000000..43c994c
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/CLAUDE.md"
@@ -0,0 +1 @@
+@AGENTS.md
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/LICENSE" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/LICENSE"
new file mode 100644
index 0000000..30b20e3
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/LICENSE"
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/app.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/app.json"
new file mode 100644
index 0000000..f83a317
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/app.json"
@@ -0,0 +1,45 @@
+{
+ "expo": {
+ "name": "mobile",
+ "slug": "mobile",
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/images/icon.png",
+ "scheme": "mobile",
+ "userInterfaceStyle": "automatic",
+ "ios": {
+ "icon": "./assets/expo.icon"
+ },
+ "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"
+ },
+ "predictiveBackGestureEnabled": false,
+ "package": "com.gregorl.mobile"
+ },
+ "web": {
+ "output": "static",
+ "favicon": "./assets/images/favicon.png"
+ },
+ "plugins": [
+ "expo-router",
+ [
+ "expo-splash-screen",
+ {
+ "backgroundColor": "#208AEF",
+ "android": {
+ "image": "./assets/images/splash-icon.png",
+ "imageWidth": 76
+ }
+ }
+ ]
+ ],
+ "experiments": {
+ "typedRoutes": true,
+ "reactCompiler": true
+ }
+ }
+}
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/Assets/expo-symbol 2.svg" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/Assets/expo-symbol 2.svg"
new file mode 100644
index 0000000..51d3676
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/Assets/expo-symbol 2.svg"
@@ -0,0 +1,3 @@
+
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/Assets/grid.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/Assets/grid.png"
new file mode 100644
index 0000000..eefea24
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/Assets/grid.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/icon.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/icon.json"
new file mode 100644
index 0000000..7a2c33c
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/expo.icon/icon.json"
@@ -0,0 +1,40 @@
+{
+ "fill" : {
+ "automatic-gradient" : "extended-srgb:0.00000,0.47843,1.00000,1.00000"
+ },
+ "groups" : [
+ {
+ "layers" : [
+ {
+ "image-name" : "expo-symbol 2.svg",
+ "name" : "expo-symbol 2",
+ "position" : {
+ "scale" : 1,
+ "translation-in-points" : [
+ 1.1008400065293245e-05,
+ -16.046875
+ ]
+ }
+ },
+ {
+ "image-name" : "grid.png",
+ "name" : "grid"
+ }
+ ],
+ "shadow" : {
+ "kind" : "neutral",
+ "opacity" : 0.5
+ },
+ "translucency" : {
+ "enabled" : true,
+ "value" : 0.5
+ }
+ }
+ ],
+ "supported-platforms" : {
+ "circles" : [
+ "watchOS"
+ ],
+ "squares" : "shared"
+ }
+}
\ No newline at end of file
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-background.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-background.png"
new file mode 100644
index 0000000..5ffefc5
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-background.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-foreground.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-foreground.png"
new file mode 100644
index 0000000..3a9e501
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-foreground.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-monochrome.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-monochrome.png"
new file mode 100644
index 0000000..77484eb
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/android-icon-monochrome.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-badge-white.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-badge-white.png"
new file mode 100644
index 0000000..2863067
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-badge-white.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-badge.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-badge.png"
new file mode 100644
index 0000000..5d5c5bb
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-badge.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-logo.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-logo.png"
new file mode 100644
index 0000000..6b1642a
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/expo-logo.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/favicon.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/favicon.png"
new file mode 100644
index 0000000..408bd74
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/favicon.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/icon.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/icon.png"
new file mode 100644
index 0000000..67c777a
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/icon.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/logo-glow.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/logo-glow.png"
new file mode 100644
index 0000000..edc99be
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/logo-glow.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo.png"
new file mode 100644
index 0000000..9d72a9f
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo@2x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo@2x.png"
new file mode 100644
index 0000000..2229b13
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo@2x.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo@3x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo@3x.png"
new file mode 100644
index 0000000..a99b203
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/react-logo@3x.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/splash-icon.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/splash-icon.png"
new file mode 100644
index 0000000..6b1642a
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/splash-icon.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore.png"
new file mode 100644
index 0000000..73d8258
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore@2x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore@2x.png"
new file mode 100644
index 0000000..21b9bd2
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore@2x.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore@3x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore@3x.png"
new file mode 100644
index 0000000..422202d
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/explore@3x.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home.png"
new file mode 100644
index 0000000..ad5699c
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home@2x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home@2x.png"
new file mode 100644
index 0000000..22a1f2c
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home@2x.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home@3x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home@3x.png"
new file mode 100644
index 0000000..f5d1f9a
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tabIcons/home@3x.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tutorial-web.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tutorial-web.png"
new file mode 100644
index 0000000..e4a8c58
Binary files /dev/null and "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/assets/images/tutorial-web.png" differ
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/metro.config.js" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/metro.config.js"
new file mode 100644
index 0000000..b549ebe
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/metro.config.js"
@@ -0,0 +1,19 @@
+// Learn more: https://docs.expo.dev/guides/monorepos/
+const { getDefaultConfig } = require('expo/metro-config');
+const path = require('path');
+
+const projectRoot = __dirname;
+const monorepoRoot = path.resolve(projectRoot, '../..');
+
+const config = getDefaultConfig(projectRoot);
+
+// Watch the whole monorepo so changes in packages/* trigger rebuilds.
+config.watchFolders = [monorepoRoot];
+
+// Resolve modules from the app's node_modules first, then the workspace root.
+config.resolver.nodeModulesPaths = [
+ path.resolve(projectRoot, 'node_modules'),
+ path.resolve(monorepoRoot, 'node_modules'),
+];
+
+module.exports = config;
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/package.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/package.json"
new file mode 100644
index 0000000..96c0589
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/package.json"
@@ -0,0 +1,46 @@
+{
+ "name": "mobile",
+ "main": "expo-router/entry",
+ "version": "1.0.0",
+ "dependencies": {
+ "@expo/ui": "~56.0.14",
+ "@<@var(context.project.name)>/rpc": "workspace:*",
+ "expo": "~56.0.5",
+ "expo-constants": "~56.0.16",
+ "expo-crypto": "~56.0.4",
+ "expo-dev-client": "~56.0.18",
+ "expo-device": "~56.0.4",
+ "expo-font": "~56.0.5",
+ "expo-glass-effect": "~56.0.4",
+ "expo-image": "~56.0.9",
+ "expo-linking": "~56.0.12",
+ "expo-router": "~56.2.7",
+ "expo-splash-screen": "~56.0.10",
+ "expo-status-bar": "~56.0.4",
+ "expo-symbols": "~56.0.5",
+ "expo-system-ui": "~56.0.5",
+ "expo-web-browser": "~56.0.5",
+ "react": "19.2.3",
+ "react-dom": "19.2.3",
+ "react-native": "0.85.3",
+ "react-native-gesture-handler": "~2.31.1",
+ "react-native-reanimated": "4.3.1",
+ "react-native-safe-area-context": "~5.7.0",
+ "react-native-screens": "4.25.2",
+ "react-native-web": "~0.21.0",
+ "react-native-worklets": "0.8.3"
+ },
+ "devDependencies": {
+ "@types/react": "~19.2.2",
+ "typescript": "~6.0.3"
+ },
+ "scripts": {
+ "start": "expo start",
+ "reset-project": "node ./scripts/reset-project.js",
+ "android": "expo run:android",
+ "ios": "expo run:ios",
+ "web": "expo start --web",
+ "lint": "expo lint"
+ },
+ "private": true
+}
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/src/app/_layout.tsx" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/src/app/_layout.tsx"
new file mode 100644
index 0000000..d2a8b0b
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/src/app/_layout.tsx"
@@ -0,0 +1,5 @@
+import { Stack } from "expo-router";
+
+export default function RootLayout() {
+ return ;
+}
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/src/app/index.tsx" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/src/app/index.tsx"
new file mode 100644
index 0000000..7417679
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/src/app/index.tsx"
@@ -0,0 +1,73 @@
+import { createRouter, Todo } from "@<@var(context.project.name)>/rpc"
+import { useEffect, useState } from "react"
+import { ScrollView, Button, Checkbox, Host, Column, TextInput, Text, useNativeState, Row, Icon } from "@expo/ui";
+import * as Crypto from "expo-crypto"
+import { colorInvert, controlSize } from "@expo/ui/swift-ui/modifiers";
+import { fillMaxWidth, padding, width } from "@expo/ui/jetpack-compose/modifiers";
+export default function Index() {
+ const router = createRouter("http://10.0.2.2:8080")
+ const [todos, setTodos] = useState>([])
+ const todoToCreateTask = useNativeState("")
+ const fetchTodos = () => {
+ router.todos.listTodos({}).then((r) => {
+ setTodos(r.todos)
+ })
+ }
+ useEffect(() => {
+ fetchTodos();
+ })
+
+ const setTodoDone = (id: string, task: string) => {
+ return (done: boolean) => {
+ router.todos.updateTodo({ todo: { id, task, done } })
+ fetchTodos()
+ }
+ }
+
+ const deleteTodo = (id: string) => {
+ return () => {
+ router.todos.deleteTodo({ todo: { id } })
+ fetchTodos()
+ }
+ }
+
+ const createTodo = () => {
+ router.todos.createTodo({ todo: { id: Crypto.randomUUID(), task: todoToCreateTask.value } }).then((r) => {
+ console.log(r)
+ fetchTodos()
+ }).catch((e) => {
+ console.log(e)
+ })
+ }
+
+ const updateTodoToCreateTask = (task: string) => {
+ todoToCreateTask.value = task
+ }
+
+ return (
+
+
+ create todo
+
+
+
+ {
+ todos.map((todo) => (
+
+
+ {todo.task}
+
+
+
+
+
+
+
+
+ ))
+ }
+
+
+
+ )
+}
diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/tsconfig.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/tsconfig.json"
new file mode 100644
index 0000000..2e9a669
--- /dev/null
+++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>/tsconfig.json"
@@ -0,0 +1,20 @@
+{
+ "extends": "expo/tsconfig.base",
+ "compilerOptions": {
+ "strict": true,
+ "paths": {
+ "@/*": [
+ "./src/*"
+ ],
+ "@/assets/*": [
+ "./assets/*"
+ ]
+ }
+ },
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ ".expo/types/**/*.ts",
+ "expo-env.d.ts"
+ ]
+}
diff --git a/template/devenv.nix b/template/devenv.nix
index 936f7d8..645f0cb 100644
--- a/template/devenv.nix
+++ b/template/devenv.nix
@@ -1,4 +1,10 @@
-{ pkgs, lib, config, inputs, ... }:
+<@if(neq(context.project.frontend,"none"))>
+ bundev = {
+ exec = "bun dev";
+ cwd = "./apps/web";
+ after= ["devenv:processes:air@started"];
+ };
+ <@endif>{ pkgs, lib, config, inputs, ... }:
{
packages = [
@@ -13,8 +19,27 @@
pkgs.protoc-gen-connect-go
pkgs.protoc-gen-es
pkgs.cobra-cli
+ <@if(eq(context.project.mobile,"expo"))>
+ pkgs.glib
+ <@endif>
];
-
+ <@if(eq(context.project.mobile,"expo"))>
+ android = {
+ enable = true;
+ emulator = {
+ enable = true;
+ };
+ buildTools.version = ["34.0.0" "35.0.0" "36.0.0" ]; # add 36.0.0
+ reactNative.enable = true;
+ android-studio = {
+ enable = false;
+ };
+ ndk = {
+ enable = true;
+ version = [ "27.1.12297006" ];
+ };
+ };
+ <@endif>
languages.go.enable = true;
languages.typescript.enable = true;
services.postgres = {
@@ -28,6 +53,21 @@
}
];
};
+ <@if(eq(context.project.mobile,"expo"))>
+ enterShell = ''
+ export LD_LIBRARY_PATH=$ANDROID_HOME/emulator/lib64:$LD_LIBRARY_PATH
+ '';
+ tasks.'<@var(context.project.name)>:create-avd'.exec = ''
+ avdmanager create avd
+ -n "Pixel_5_API34"
+ -k "system-images;android-34;google_apis_playstore;x86_64"
+ -d "pixel_5"
+ '';
+ tasks.'<@var(context.project.name)>:run-emulator' = {
+ exec = "emulator -avd Pixel_5_API34";
+ after = [ "<@var(context.project.name)>:create-avd" ]
+ };
+ <@endif>
processes = {
air = {
exec = "air";
@@ -49,12 +89,11 @@
cwd = "./services/api";
after= ["devenv:processes:air@started"];
};
- <@if(neq(context.project.frontend,"none"))>
- bundev = {
- exec = "bun dev";
- cwd = "./apps/web";
- after= ["devenv:processes:air@started"];
- };
+ <@if(eq(context.project.mobile,"expo"))>
+ emulator = {
+ exec
+ }
<@endif>
+
};
}
diff --git a/template/devenv.yaml b/template/devenv.yaml
index 116a2ad..fe1413a 100644
--- a/template/devenv.yaml
+++ b/template/devenv.yaml
@@ -1,4 +1,7 @@
-# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
+<@if(context.project.mobile.expo)>
+nixpkgs:
+ allowUnfree: true
+<@endif>
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling