0.0.9
Publish npm package / publish (push) Successful in 26s

version bump
This commit is contained in:
2026-10-08 09:42:06 +02:00
parent 8e3abca9d7
commit 2fab51878f
26 changed files with 342 additions and 175 deletions
@@ -1,21 +1,25 @@
{
"name": "example-bare",
"name": "web",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"start": "vite start",
"preview": "vite preview"
"start": "node .output/server/index.mjs",
"preview": "vite preview",
"check": "tsc --noEmit"
},
"dependencies": {
"@<@var(context.project.name)>/rpc": "workspace:*",
"@solidjs/start": "2.0.0-alpha.2",
"@solidjs/vite-plugin-nitro-2": "^0.1.0",
"solid-js": "^1.9.5",
"vite": "^7.0.0"
"@solidjs/start": "^2.0.0",
"solid-js": "^1.9.14",
"vite": "^8.0.0",
"nitro": "^3.0.260610-beta",
"gsap": "^3.15.0"
},
"engines": {
"node": ">=22"
"node": ">=24"
},
"devDependencies": {}
"devDependencies": {
"typescript": "^6.0.3"
}
}
@@ -1,61 +1,5 @@
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);
}
main { max-width: 32rem; margin: 2rem auto; font-family: system-ui, sans-serif; }
form, .todo-row { display: flex; gap: 0.75rem; align-items: center; margin-bottom: 0.75rem; }
input[type="text"] { flex: 1; padding: 0.5rem; border: 1px solid #8e8e93; border-radius: 8px; }
.todo-row span { flex: 1; }
.offline { color: #d32f2f; }
@@ -1,7 +1,10 @@
import { createSignal, For, onCleanup, onMount, Show } from "solid-js";
import { gsap } from "gsap";
import { Flip } from "gsap/Flip";
import { createRouter, Todo } from "@<@var(context.project.name)>/rpc"
import "./app.css";
gsap.registerPlugin(Flip)
const router = createRouter("http://127.0.0.1:8080")
// Changes made elsewhere (another tab, the mobile app) show up within this interval.
const syncIntervalMs = 2000
@@ -10,11 +13,25 @@ export default function App() {
const [todos, setTodos] = createSignal<Todo[]>([]);
const [offline, setOffline] = createSignal(false);
const [todoToCreateTask, setTodoToCreateTask] = createSignal<string>("");
// Like the mobile app: rows spring into their new place when the list re-sorts, new rows fade in.
// Solid recreates rows for new objects; data-flip-id lets Flip match them to the old ones.
const showTodos = (next: Todo[]) => {
const rows = Flip.getState(".todo-row")
setTodos(next)
Flip.from(rows, {
targets: ".todo-row",
duration: 0.5,
ease: "back.out(1.4)",
onEnter: (entering) => gsap.fromTo(entering, { opacity: 0 }, { opacity: 1, duration: 0.3 }),
})
}
const fetchTodos = () => {
router.todos.listTodos({}).then((r) => {
setOffline(false)
// Polling returns the same list most of the time; keep the old array so <For> keeps its rows.
if (JSON.stringify(todos()) !== JSON.stringify(r.todos)) setTodos(r.todos)
// Polling returns the same list most of the time; skip re-rendering it.
if (JSON.stringify(todos()) !== JSON.stringify(r.todos)) showTodos(r.todos)
}).catch(() => setOffline(true))
}
onMount(() => {
@@ -30,7 +47,8 @@ export default function App() {
}
const deleteTodo = (id: string) => {
return () => {
return async (event: Event & { currentTarget: HTMLElement }) => {
await gsap.to(event.currentTarget.closest(".todo-row"), { opacity: 0, duration: 0.3 })
router.todos.deleteTodo({ todo: { id } }).then(fetchTodos, () => setOffline(true))
}
}
@@ -45,20 +63,22 @@ export default function App() {
}
return (
<div>
<p>Create Todo</p>
<Show when={offline()}><p style={{ color: "#d32f2f" }}>Can't reach the API, retrying…</p></Show>
<input value={todoToCreateTask()} onInput={(e) => setTodoToCreateTask(e.currentTarget.value)} type="text" placeholder="What needs to be done?"/>
<button onclick={createTodo}> create </button>
<main>
<h1>Create Todo</h1>
<Show when={offline()}><p class="offline">Can't reach the API, retrying…</p></Show>
<form onSubmit={(event) => { event.preventDefault(); createTodo() }}>
<input value={todoToCreateTask()} onInput={(e) => setTodoToCreateTask(e.currentTarget.value)} type="text" placeholder="What needs to be done?"/>
<button>create Todo</button>
</form>
<For each={todos()}>
{(item:Todo) =>
<div>
{item.task}
<input type='checkbox' checked={item.done} onChange={setTodoDone(item.id || "",item.task)}/>
<button onclick={deleteTodo(item.id || "")}>delete</button>
</div>
}
{(todo: Todo) =>
<div class="todo-row" data-flip-id={todo.id}>
<span>{todo.task}</span>
<input type="checkbox" checked={todo.done} onChange={setTodoDone(todo.id || "", todo.task)}/>
<button onClick={deleteTodo(todo.id || "")}>delete</button>
</div>
}
</For>
</div>
</main>
);
}
@@ -10,10 +10,15 @@
"allowJs": true,
"strict": true,
"noEmit": true,
"types": ["vite/client"],
"types": [
"vite/client"
],
"isolatedModules": true,
"paths": {
"~/*": ["./src/*"]
}
"~/*": [
"./src/*"
]
},
"skipLibCheck": true
}
}
@@ -1,10 +1,14 @@
import { defineConfig } from "vite";
import { nitroV2Plugin as nitro } from "@solidjs/vite-plugin-nitro-2";
import { nitro } from "nitro/vite";
import { solidStart } from "@solidjs/start/config";
export default defineConfig({
plugins: [solidStart(),
nitro()
]
],
// Same port as the other web templates, which the API allows via CORS.
server: { port: 5173 },
// SolidStart's dev toolbar imports this CommonJS package in the browser, which fails unless prebundled.
optimizeDeps: { include: ["@solidjs/start > @jridgewell/trace-mapping"] },
});