add solid-start support
This commit is contained in:
4
bun.lock
4
bun.lock
@@ -6,7 +6,7 @@
|
||||
"name": "glstack",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.2.0",
|
||||
"@gregorlohaus/tdir": "^0.1.1",
|
||||
"@gregorlohaus/tdir": "^0.1.2",
|
||||
"zod": "^4.3.6",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
"@clack/prompts": ["@clack/prompts@1.2.0", "", { "dependencies": { "@clack/core": "1.2.0", "fast-string-width": "^1.1.0", "fast-wrap-ansi": "^0.1.3", "sisteransi": "^1.0.5" } }, "sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w=="],
|
||||
|
||||
"@gregorlohaus/tdir": ["@gregorlohaus/tdir@0.1.1", "", { "peerDependencies": { "zod": "^4" } }, "sha512-4NlHif5Pn6Vh1TzCj8B1d+pz8ab5/CodC2Cq9HVr1wHdFlgXM/yjtZEDLdBMtwqz1n1oCCEjzV7XYbin2ywsjQ=="],
|
||||
"@gregorlohaus/tdir": ["@gregorlohaus/tdir@0.1.2", "", { "peerDependencies": { "zod": "^4" } }, "sha512-gEZg1+kwhMQQqEhMdyVBnHBrIWFMlvHt8C6sbPtY/PbbFo02odTBkpclfovIs2p4Awo0Hagzq3B6rpePGD/03w=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
|
||||
|
||||
|
||||
12
index.ts
12
index.ts
@@ -18,6 +18,15 @@ const project = await p.group(
|
||||
return undefined
|
||||
},
|
||||
}),
|
||||
frontend: async () =>
|
||||
await p.select({
|
||||
message: 'Pick a frontend framework.',
|
||||
options: [
|
||||
{value: "svelte-kit", label:"SvelteKit"},
|
||||
{value: "solid-start", label:"SolidStart"}
|
||||
]
|
||||
})
|
||||
,
|
||||
goprefix: () =>
|
||||
p.text({
|
||||
message: "What would you like to use as a go package prefix?",
|
||||
@@ -39,7 +48,8 @@ const createRenderer = initRenderer(path.join(import.meta.dir, '..', 'template')
|
||||
const render = createRenderer(z.object({
|
||||
project: z.object({
|
||||
name: z.string(),
|
||||
goprefix: z.string()
|
||||
goprefix: z.string(),
|
||||
frontend: z.literal("svelte-kit").or(z.literal("solid-start"))
|
||||
})
|
||||
}))
|
||||
const destDir = path.join("./",project.name);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.2.0",
|
||||
"@gregorlohaus/tdir": "^0.1.1",
|
||||
"@gregorlohaus/tdir": "^0.1.2",
|
||||
"zod": "^4.3.6"
|
||||
}
|
||||
}
|
||||
|
||||
28
template/apps/<@if(eq(context.project.frontend,"solid-start"))>web/.gitignore
vendored
Normal file
28
template/apps/<@if(eq(context.project.frontend,"solid-start"))>web/.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
dist
|
||||
.wrangler
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.vinxi
|
||||
app.config.timestamp_*.js
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
*.launch
|
||||
.settings/
|
||||
|
||||
# Temp
|
||||
gitignore
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -0,0 +1,32 @@
|
||||
# SolidStart
|
||||
|
||||
Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);
|
||||
|
||||
## Creating a project
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm init solid@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm init solid@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Solid apps are built with _presets_, which optimise your project for deployment to different environments.
|
||||
|
||||
By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.
|
||||
|
||||
## This project was created with the [Solid CLI](https://github.com/solidjs-community/solid-cli)
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "example-basic",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"start": "vite start",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"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": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 664 B |
@@ -0,0 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
body {
|
||||
font-family: Gordita, Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
@@ -0,0 +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 "./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<Todo>[];
|
||||
},
|
||||
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 })
|
||||
}))
|
||||
}
|
||||
})
|
||||
)
|
||||
return (
|
||||
<Router
|
||||
root={props => (
|
||||
<MetaProvider>
|
||||
<QueryClientProvider client={queryClient} >
|
||||
<TodoCollectionProvider value={todosCollection}>
|
||||
<Suspense>{props.children}</Suspense>
|
||||
</TodoCollectionProvider>
|
||||
</QueryClientProvider>
|
||||
</MetaProvider>
|
||||
)}
|
||||
>
|
||||
<FileRoutes/>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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<ExtractPayload<Todo>>({
|
||||
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 (
|
||||
<>
|
||||
<input class="border rounded-md px-3 py-1" ref={inputRef} type='text' onInput={setTask} />
|
||||
<button class="bg-teal-800 text-teal-100 p-1 rounded-md cursor-pointer" onClick={insertTodo}> create </button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
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 (
|
||||
<For each={todos()} fallback={<div>Loading...</div>}>
|
||||
{(item) => <Todo todo={item} />}
|
||||
</For>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
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<RpcTodo> }) => {
|
||||
const [todoState, setTodoState] = createSignal(todo)
|
||||
const todoCollection = useTodoCollection()
|
||||
let commitUpdateTimeoutId: NodeJS.Timeout|null = null;
|
||||
const updateTask: JSX.EventHandlerUnion<HTMLInputElement, Event> = (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<HTMLInputElement, Event> = (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 (
|
||||
<div class="flex flex-col items-center border rounded-md p-5 gap-2">
|
||||
<input class="text-center border rounded-md px-3 py-1" oninput={updateTask} type="text" value={todoState().task} />
|
||||
<span> {(new Date(todoState().createdAt || "")).toLocaleString()}</span>
|
||||
<span> {(new Date(todoState().updatesAt || "")).toLocaleString()}</span>
|
||||
<input type="checkbox" onchange={updateDone} checked={todoState().done} />
|
||||
<button class="bg-amber-800 text-amber-100 p-1 rounded-md cursor-pointer" onclick={del} class=""> delete </button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
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<ExtractPayload<Todo>>
|
||||
export const TodoCollectionContext = createContext<TodoCollection>()
|
||||
export const useTodoCollection = () => {
|
||||
const col = useContext(TodoCollectionContext)
|
||||
if (col === undefined) {
|
||||
throw new Error("Todo collection has not been initialized")
|
||||
}
|
||||
return col;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { JSXElement } from 'solid-js';
|
||||
import { TodoCollection, TodoCollectionContext } from './create'
|
||||
|
||||
export const TodoCollectionProvider = (props : {children:JSXElement, value: TodoCollection}) => {
|
||||
return (
|
||||
<TodoCollectionContext.Provider value={props.value}> {props.children} </TodoCollectionContext.Provider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// @refresh reload
|
||||
import { mount, StartClient } from "@solidjs/start/client";
|
||||
|
||||
mount(() => <StartClient />, document.getElementById("app")!);
|
||||
@@ -0,0 +1,21 @@
|
||||
// @refresh reload
|
||||
import { createHandler, StartServer } from "@solidjs/start/server";
|
||||
|
||||
export default createHandler(() => (
|
||||
<StartServer
|
||||
document={({ assets, children, scripts }) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
{assets}
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">{children}</div>
|
||||
{scripts}
|
||||
</body>
|
||||
</html>
|
||||
)}
|
||||
/>
|
||||
));
|
||||
1
template/apps/<@if(eq(context.project.frontend,"solid-start"))>web/src/global.d.ts
vendored
Normal file
1
template/apps/<@if(eq(context.project.frontend,"solid-start"))>web/src/global.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="@solidjs/start/env" />
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createRouter } from "@<@var(context.project.name)>/rpc"
|
||||
|
||||
const router = createRouter("http://127.0.0.1:8080")
|
||||
|
||||
export const getRouter = () => {
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Title } from "@solidjs/meta";
|
||||
import { HttpStatusCode } from "@solidjs/start";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<main>
|
||||
<Title>Not Found</Title>
|
||||
<HttpStatusCode code={404} />
|
||||
<h1>Page Not Found</h1>
|
||||
<p>
|
||||
Visit{" "}
|
||||
<a href="https://start.solidjs.com" target="_blank">
|
||||
start.solidjs.com
|
||||
</a>{" "}
|
||||
to learn how to build SolidStart apps.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Title } from "@solidjs/meta";
|
||||
import { CreateTodo } from "~/components/CreateTodo";
|
||||
import { ListTodos } from "~/components/ListTodos"
|
||||
export default function Home() {
|
||||
return (
|
||||
<main class="flex flex-col items-center gap-2 py-5">
|
||||
<Title>Todos</Title>
|
||||
<h1 class="text-5xl"> Todos </h1>
|
||||
<CreateTodo/>
|
||||
<ListTodos/>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"types": ["vite/client"],
|
||||
"isolatedModules": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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()
|
||||
]
|
||||
});
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user