diff --git a/index.ts b/index.ts index 1638481..2703dd2 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" } ] }) , @@ -37,6 +46,9 @@ const project = await p.group( return undefined }, }), + installDeps: async () => { + return await p.confirm({message: "Install dependencies?", }) + } }, { onCancel: () => { @@ -53,18 +65,17 @@ const render = createRenderer(z.object({ name: z.string(), goprefix: z.string(), frontend: z.string(), + mobile: 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(); -if (project.frontend !== "none") { - await Bun.$`bun install`.cwd(path.join(destDir,'apps','web')).quiet(); +if (project.installDeps) { + s.start("Installing dependencies"); + await Bun.$`bun install`.cwd(path.join(destDir)).quiet(); + s.stop("Dependencies installed."); } -s.stop("Dependencies installed."); p.outro("You're all set!"); diff --git a/package.json b/package.json index 885695f..8362023 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "create-glstack", - "version": "0.0.7", + "version": "0.0.8", "type": "module", "license": "MIT", "bin": { diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/.ignore" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/.ignore" deleted file mode 100644 index 3c3629e..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/.ignore" +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/package.json" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/package.json" index 33f0f0b..1546f3b 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/package.json" +++ "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/package.json" @@ -1,5 +1,5 @@ { - "name": "example-basic", + "name": "example-bare", "type": "module", "scripts": { "dev": "vite dev", @@ -9,16 +9,9 @@ }, "dependencies": { "@<@var(context.project.name)>/rpc": "workspace:*", - "@solidjs/meta": "^0.29.4", - "@solidjs/router": "^0.15.0", "@solidjs/start": "2.0.0-alpha.2", "@solidjs/vite-plugin-nitro-2": "^0.1.0", - "@tailwindcss/vite": "^4.2.2", - "@tanstack/query-db-collection": "^1.0.35", - "@tanstack/solid-db": "^0.2.18", - "@tanstack/solid-query": "^5.96.2", "solid-js": "^1.9.5", - "tailwindcss": "^4.2.2", "vite": "^7.0.0" }, "engines": { diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.css" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.css" index c9cc343..a4d2e55 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.css" +++ "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.css" @@ -1,5 +1,61 @@ -@import "tailwindcss"; - body { font-family: Gordita, Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; } + +a { + margin-right: 1rem; +} + +main { + text-align: center; + padding: 1em; + margin: 0 auto; +} + +h1 { + color: #335d92; + text-transform: uppercase; + font-size: 4rem; + font-weight: 100; + line-height: 1.1; + margin: 4rem auto; + max-width: 14rem; +} + +p { + max-width: 14rem; + margin: 2rem auto; + line-height: 1.35; +} + +@media (min-width: 480px) { + h1 { + max-width: none; + } + + p { + max-width: none; + } +} + +.increment { + font-family: inherit; + font-size: inherit; + padding: 1em 2em; + color: #335d92; + background-color: rgba(68, 107, 158, 0.1); + border-radius: 2em; + border: 2px solid rgba(68, 107, 158, 0); + outline: none; + width: 200px; + font-variant-numeric: tabular-nums; + cursor: pointer; +} + +.increment:focus { + border: 2px solid #335d92; +} + +.increment:active { + background-color: rgba(68, 107, 158, 0.2); +} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.tsx" index 5ff9bcc..ccab463 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.tsx" +++ "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/app.tsx" @@ -1,58 +1,58 @@ -import { MetaProvider, Title } from "@solidjs/meta"; -import { Router } from "@solidjs/router"; -import { FileRoutes } from "@solidjs/start/router"; -import { Suspense } from "solid-js"; -import { createCollection } from '@tanstack/solid-db' -import { queryCollectionOptions } from '@tanstack/query-db-collection' -import type { Todo, ExtractPayload } from '@<@var(context.project.name)>/rpc' -import { QueryClient, QueryClientProvider } from "@tanstack/solid-query" -import { getRouter } from "./lib/getRouter" +import { createSignal, For } from "solid-js"; +import { createRouter, Todo } from "@<@var(context.project.name)>/rpc" +import { createEffect } from 'solid-js' import "./app.css"; -import { TodoCollectionProvider } from "./context/todocollection/provider"; -const queryClient = new QueryClient({ -}) -const router = getRouter(); export default function App() { - const todosCollection = createCollection( - queryCollectionOptions({ - queryKey: ["todos"], - queryFn: async () => { - const todos = await router.todos.listTodos({}) - return todos.todos as ExtractPayload[]; - }, - queryClient, - getKey: (item) => item.id ? item.id : crypto.randomUUID(), - onInsert: async ({ transaction }) => { - Promise.all(transaction.mutations.map((m) => { - router.todos.createTodo({ todo: m.modified }) - })) - }, - onDelete: async ({ transaction }) => { - Promise.all(transaction.mutations.map((m) => { - router.todos.deleteTodo({ todo: m.modified }) - })) - }, - onUpdate: async ({ transaction }) => { - Promise.all(transaction.mutations.map((m) => { - router.todos.updateTodo({ todo: m.modified }) - })) - } + const router = createRouter("http://127.0.0.1:8080") + const [todos, setTodos] = createSignal([]); + const [todoToCreateTask, setTodoToCreateTask] = createSignal(""); + const fetchTodos = () => { + router.todos.listTodos({}).then((r) => { + setTodos(r.todos) }) - ) + } + createEffect(() => { + fetchTodos() + }) + + const setTodoDone = (id: string, task: string) => { + return async (event : Event & { currentTarget: HTMLInputElement }) => { + await router.todos.updateTodo({ todo: { id, task, done: event.currentTarget.checked } }) + fetchTodos() + } + } + + const deleteTodo = (id: string) => { + return async () => { + await router.todos.deleteTodo({ todo: { id } }) + fetchTodos() + } + } + + const createTodo = () => { + router.todos.createTodo({ todo: { id: crypto.randomUUID(), task: todoToCreateTask() } }).then((r) => { + console.log(r) + fetchTodos() + }).catch((e) => { + console.log(e) + }) + } + return ( - ( - - - - {props.children} - - - - )} - > - - +
+

Create Todo

+ setTodoToCreateTask(e.currentTarget.value)} type="text"/> + + + {(item:Todo) => +
+ {item.task} + + +
+ } +
+
); } diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/CreateTodo.tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/CreateTodo.tsx" deleted file mode 100644 index 61c450e..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/CreateTodo.tsx" +++ /dev/null @@ -1,38 +0,0 @@ -import { ExtractPayload, type Todo } from '@<@var(context.project.name)>/rpc' -import { createSignal } from 'solid-js'; -import { useTodoCollection } from '~/context/todocollection/create'; - -export const CreateTodo = () => { - const [todoState, setTodoState] = createSignal>({ - id: crypto.randomUUID(), - task: "", - done: false, - }) - - let inputRef!: HTMLInputElement - - const setTask = () => { - const todo = {...todoState()} - todo.task = inputRef.value; - setTodoState(todo) - } - - const todoCollection = useTodoCollection() - - const insertTodo = () => { - todoCollection.insert(todoState()) - setTodoState({ - id: crypto.randomUUID(), - task: "", - done: false - }) - inputRef.value = ""; - } - - return ( - <> - - - - ) -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/ListTodos.tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/ListTodos.tsx" deleted file mode 100644 index 3df92ba..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/ListTodos.tsx" +++ /dev/null @@ -1,29 +0,0 @@ -import { useLiveQuery } from "@tanstack/solid-db"; -import { useTodoCollection } from "~/context/todocollection/create"; -import { Todo } from './Todo' -import { For } from 'solid-js' - -export const ListTodos = () => { - const todoCollection = useTodoCollection() - const data = useLiveQuery((q) => - q.from({todos: todoCollection}) - ) - const todos = () => { - const items = Array.from(data.state.values()); - return items.sort((a: any, b: any) => { - if (a.done != b.done) return a.done ? -1 : 1 - if (!a.done && !b.done) { - const adate = a.createdAt ? new Date(a.createdAt) : new Date() - const bdate = b.createdAt ? new Date(b.createdAt) : new Date() - return bdate.getTime() - adate.getTime() - } - return 0 - }) - } - - return ( - Loading...}> - {(item) => } - - ) -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/Todo.tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/Todo.tsx" deleted file mode 100644 index 56edeb2..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/components/Todo.tsx" +++ /dev/null @@ -1,44 +0,0 @@ -import { ExtractPayload, type Todo as RpcTodo } from '@<@var(context.project.name)>/rpc' -import { createSignal, type JSX } from 'solid-js'; -import { useTodoCollection } from '~/context/todocollection/create'; - -export const Todo = ({ todo }: { todo: ExtractPayload }) => { - const [todoState, setTodoState] = createSignal(todo) - const todoCollection = useTodoCollection() - let commitUpdateTimeoutId: NodeJS.Timeout|null = null; - const updateTask: JSX.EventHandlerUnion = (e) => { - if (commitUpdateTimeoutId != null) { - clearTimeout(commitUpdateTimeoutId) - } - const todo = { ...todoState() }; - todo.task = e.currentTarget.value - setTodoState(todo) - commitUpdateTimeoutId = setTimeout(() => { - todoCollection.update(todoState().id, (draft) => { - draft.task = todoState().task - }) - },3000) - - } - const updateDone: JSX.EventHandlerUnion = (e) => { - const todo = { ...todoState() } - todo.done = e.currentTarget.checked - setTodoState(todo) - todoCollection.update(todoState().id, (draft) => { - draft.done = todoState().done - }) - } - const del = () => { - todoCollection.delete(todoState().id || "") - } - return ( -
- - {(new Date(todoState().createdAt || "")).toLocaleString()} - {(new Date(todoState().updatesAt || "")).toLocaleString()} - - -
- ) -} - diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/context/todocollection/create.ts" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/context/todocollection/create.ts" deleted file mode 100644 index 58343d7..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/context/todocollection/create.ts" +++ /dev/null @@ -1,12 +0,0 @@ -import { createContext,useContext } from 'solid-js' -import { type CollectionImpl, type CollectionLike } from '@tanstack/solid-db' -import type { ExtractPayload, Todo } from '@<@var(context.project.name)>/rpc'; -export type TodoCollection = CollectionImpl> -export const TodoCollectionContext = createContext() -export const useTodoCollection = () => { - const col = useContext(TodoCollectionContext) - if (col === undefined) { - throw new Error("Todo collection has not been initialized") - } - return col; -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/context/todocollection/provider.tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/context/todocollection/provider.tsx" deleted file mode 100644 index a671753..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/context/todocollection/provider.tsx" +++ /dev/null @@ -1,8 +0,0 @@ -import { JSXElement } from 'solid-js'; -import { TodoCollection, TodoCollectionContext } from './create' - -export const TodoCollectionProvider = (props : {children:JSXElement, value: TodoCollection}) => { - return ( - {props.children} - ) -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/lib/getRouter.ts" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/lib/getRouter.ts" deleted file mode 100644 index ae11412..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/lib/getRouter.ts" +++ /dev/null @@ -1,7 +0,0 @@ -import { createRouter } from "@<@var(context.project.name)>/rpc" - -const router = createRouter("http://127.0.0.1:8080") - -export const getRouter = () => { - return router; -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/routes/[...404].tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/routes/[...404].tsx" deleted file mode 100644 index 4ea71ec..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/routes/[...404].tsx" +++ /dev/null @@ -1,19 +0,0 @@ -import { Title } from "@solidjs/meta"; -import { HttpStatusCode } from "@solidjs/start"; - -export default function NotFound() { - return ( -
- Not Found - -

Page Not Found

-

- Visit{" "} - - start.solidjs.com - {" "} - to learn how to build SolidStart apps. -

-
- ); -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/routes/index.tsx" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/routes/index.tsx" deleted file mode 100644 index 569b218..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/src/routes/index.tsx" +++ /dev/null @@ -1,13 +0,0 @@ -import { Title } from "@solidjs/meta"; -import { CreateTodo } from "~/components/CreateTodo"; -import { ListTodos } from "~/components/ListTodos" -export default function Home() { - return ( -
- Todos -

Todos

- - -
- ); -} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/vite.config.ts" "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/vite.config.ts" index 72dec74..4c93687 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/vite.config.ts" +++ "b/template/apps/<@if(eq(context.project.frontend,\"solid-start\"))>web/vite.config.ts" @@ -1,12 +1,10 @@ import { defineConfig } from "vite"; import { nitroV2Plugin as nitro } from "@solidjs/vite-plugin-nitro-2"; -import tailwindcss from '@tailwindcss/vite' + import { solidStart } from "@solidjs/start/config"; export default defineConfig({ - plugins: [ - solidStart(), - nitro(), - tailwindcss() + plugins: [solidStart(), + nitro() ] }); diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/package.json" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/package.json" index 02359de..322e3f3 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/package.json" +++ "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/package.json" @@ -21,14 +21,6 @@ "vite": "^8.0.7" }, "dependencies": { - "@bufbuild/protobuf": "^2.11.0", - "@connectrpc/connect": "^2.1.1", - "@connectrpc/connect-web": "^2.1.1", - "@<@var(context.project.name)>/rpc": "workspace:*", - "@tailwindcss/vite": "^4.3.0", - "@tanstack/query-db-collection": "^1.0.33", - "@tanstack/svelte-db": "^0.1.79", - "@tanstack/svelte-query": "^6.1.13", - "tailwindcss": "^4.3.0" + "@<@var(context.project.name)>/rpc": "workspace:*" } } diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/app.css" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/app.css" deleted file mode 100644 index 798d8f1..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/app.css" +++ /dev/null @@ -1 +0,0 @@ -import @tailwindcss; diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/CreateTodo.svelte" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/CreateTodo.svelte" deleted file mode 100644 index 700b533..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/CreateTodo.svelte" +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/ListTodos.svelte" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/ListTodos.svelte" deleted file mode 100644 index 805717c..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/ListTodos.svelte" +++ /dev/null @@ -1,29 +0,0 @@ - - -{#if data.isLoading} -
Loading...
-{:else} - {#each todos as todo (todo.id)} - - {/each} -{/if} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/Todo.svelte" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/Todo.svelte" deleted file mode 100644 index 5d395e6..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/components/Todo.svelte" +++ /dev/null @@ -1,48 +0,0 @@ - - -
- - {new Date(todoState.createdAt || '').toLocaleString()} - {new Date(todoState.updatesAt || '').toLocaleString()} - - -
diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/getconnectrouter.ts" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/getconnectrouter.ts" deleted file mode 100644 index 8ee292c..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/getconnectrouter.ts" +++ /dev/null @@ -1,8 +0,0 @@ -import {createRouter} from '@<@var(context.project.name)>/rpc' - -const router = createRouter("http://127.0.0.1:8080") - -export const getRouter = () => { - return router; -} - diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/todocollectionscontext.ts" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/todocollectionscontext.ts" deleted file mode 100644 index bf3d71f..0000000 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/lib/todocollectionscontext.ts" +++ /dev/null @@ -1,4 +0,0 @@ -import { createContext } from "svelte"; -import { type CollectionImpl } from '@tanstack/svelte-db' -import type { Todo, ExtractPayload } from "@<@var(context.project.name)>/rpc"; -export const [getTodoCollection,setTodoCollection] = createContext,string>>() diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+layout.svelte" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+layout.svelte" index 2193962..9cebde5 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+layout.svelte" +++ "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+layout.svelte" @@ -1,53 +1,11 @@ + + + - - {@render children()} - +{@render children()} diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+page.svelte" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+page.svelte" index 3c35aa9..f358f96 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+page.svelte" +++ "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/src/routes/+page.svelte" @@ -1,11 +1,51 @@ - -
- Todos -

Todos

- - -
+
+

Create Todo

+ + + {#each todos as todo (todo.id)} +
+ {todo.task} + + +
+ {/each} +
diff --git "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/vite.config.ts" "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/vite.config.ts" index 5734c85..bbf8c7d 100644 --- "a/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/vite.config.ts" +++ "b/template/apps/<@if(eq(context.project.frontend,\"svelte-kit\"))>web/vite.config.ts" @@ -1,9 +1,6 @@ import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; -import tailwindcss from '@tailwindcss/vite' + export default defineConfig({ - plugins: [ - tailwindcss(), - sveltekit(), - ] + plugins: [sveltekit()] }); diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.claude/settings.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.claude/settings.json" new file mode 100644 index 0000000..176e6a5 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.claude/settings.json" @@ -0,0 +1,5 @@ +{ + "enabledPlugins": { + "expo@claude-plugins-official": true + } +} diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.gitignore" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.gitignore" new file mode 100644 index 0000000..4b00baf --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.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\"))>mobile/.ignore" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.ignore" new file mode 100644 index 0000000..52e5644 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.ignore" @@ -0,0 +1,4 @@ +.expo +android +node_modules +assets diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.vscode/extensions.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.vscode/extensions.json" new file mode 100644 index 0000000..b7ed837 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.vscode/extensions.json" @@ -0,0 +1 @@ +{ "recommendations": ["expo.vscode-expo-tools"] } diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.vscode/settings.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.vscode/settings.json" new file mode 100644 index 0000000..e2798e4 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/.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\"))>mobile/AGENTS.md" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/AGENTS.md" new file mode 100644 index 0000000..a26b4bb --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/CLAUDE.md" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/CLAUDE.md" new file mode 100644 index 0000000..43c994c --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/CLAUDE.md" @@ -0,0 +1 @@ +@AGENTS.md diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/LICENSE" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/LICENSE" new file mode 100644 index 0000000..30b20e3 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/app.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/app.json" new file mode 100644 index 0000000..f83a317 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/expo.icon/Assets/expo-symbol 2.svg" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/expo.icon/Assets/expo-symbol 2.svg" @@ -0,0 +1,3 @@ + + + diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/expo.icon/Assets/grid.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/expo.icon/Assets/grid.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/expo.icon/icon.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/expo.icon/icon.json" new file mode 100644 index 0000000..7a2c33c --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/android-icon-background.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/android-icon-background.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/android-icon-foreground.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/android-icon-foreground.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/android-icon-monochrome.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/android-icon-monochrome.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/expo-badge-white.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/expo-badge-white.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/expo-badge.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/expo-badge.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/expo-logo.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/expo-logo.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/favicon.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/favicon.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/icon.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/icon.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/logo-glow.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/logo-glow.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/react-logo.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/react-logo.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/react-logo@2x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/react-logo@2x.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/react-logo@3x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/react-logo@3x.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/splash-icon.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/splash-icon.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tabIcons/explore.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tabIcons/explore.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tabIcons/explore@2x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tabIcons/explore@2x.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tabIcons/explore@3x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tabIcons/explore@3x.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tabIcons/home.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tabIcons/home.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tabIcons/home@2x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tabIcons/home@2x.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tabIcons/home@3x.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tabIcons/home@3x.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/assets/images/tutorial-web.png" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/assets/images/tutorial-web.png" differ diff --git "a/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/metro.config.js" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/metro.config.js" new file mode 100644 index 0000000..b549ebe --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/package.json" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/package.json" new file mode 100644 index 0000000..96c0589 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/src/app/_layout.tsx" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/src/app/_layout.tsx" new file mode 100644 index 0000000..89f0ac7 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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\"))>mobile/src/app/index.tsx" "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/src/app/index.tsx" new file mode 100644 index 0000000..8081223 --- /dev/null +++ "b/template/apps/<@if(eq(context.project.mobile,\"expo\"))>mobile/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 + +