Skip to content

feat(add-on): legend state #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { observable } from "@legendapp/state";
import { ObservablePersistLocalStorage } from "@legendapp/state/persist-plugins/local-storage";
import { syncObservable } from "@legendapp/state/sync";

type Todo = {
id: number;
text: string;
completed: boolean;
};
// Create an observable
export const todos$ = observable<Todo[]>([]);

// Persist the observable
syncObservable(todos$, {
persist: {
name: "demo-legend-state-todos",
plugin: ObservablePersistLocalStorage,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { <% if (fileRouter) { %>createFileRoute<% } else { %>createRoute<% } %> } from '@tanstack/react-router'
import { todos$ } from "@/lib/demo-legend-state";
import { For, useObservable } from "@legendapp/state/react";
import { $React } from "@legendapp/state/react-web";
<% if (codeRouter) { %>
import type { RootRoute } from '@tanstack/react-router'
<% } else { %>
export const Route = createFileRoute('/demo/legend-state')({
component: LegendStateDemo,
})
<% } %>

function TodoForm() {
const todoText$ = useObservable("");
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (todoText$.peek().trim() === "") return;
todos$.push({ id: Date.now(), text: todoText$.peek().trim(), completed: false });
todoText$.set("");
};
return (
<form onSubmit={handleSubmit}>
<$React.input
placeholder="Add a todo"
type="text"
$value={todoText$}
className="bg-white/10 rounded-lg px-4 py-2 outline-none border border-white/20 hover:border-white/40 focus:border-white/60 transition-colors duration-200 placeholder-white/40 w-full"
/>
</form>
);
}
function TodoList() {
return (
<ul className="space-y-4">
<For each={todos$} optimized>
{(todo) => (
<li
key={todo.id.get()}
className="inline-flex items-center gap-2 justify-between w-full"
>
<span className={todo.completed.get() ? "line-through" : ""}>
{todo.text.get()}
</span>
<span className="flex items-center gap-2 justify-center">
<$React.input
type="checkbox"
$checked={todo.completed}
className="w-6 h-6 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
<button
type="button"
onClick={() =>
todos$.splice(
todos$.findIndex((t) => t.id.get() === todo.id.get()),
1,
)
}
className="focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-xs px-5 py-2.5 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900"
>
Remove
</button>
</span>
</li>
)}
</For>
</ul>
);
}

function LegendStateDemo() {
return (
<div
className="min-h-[calc(100vh-32px)] text-white p-8 flex items-center justify-center w-full h-full"
style={{
backgroundImage:
"radial-gradient(50% 50% at 80% 80%, #f4a460 0%, #8b4513 70%, #1a0f0a 100%)",
}}
>
<div className="bg-white/10 backdrop-blur-lg rounded-xl p-8 shadow-lg flex flex-col gap-4 text-3xl w-5xl">
<h1 className="text-4xl font-bold mb-5">Legend State Example</h1>
<TodoForm />
<TodoList />
</div>
</div>
);
}


<% if (codeRouter) { %>
export default (parentRoute: RootRoute) => createRoute({
path: '/demo/legend-state',
component: LegendStateDemo,
getParentRoute: () => parentRoute,
})
<% } %>
13 changes: 13 additions & 0 deletions packages/cta-engine/templates/react/add-on/legend-state/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "Legend State",
"description": "A state manager with built-in sync engine to persist state locally or remotely",
"phase": "add-on",
"templates": ["file-router", "code-router"],
"link": "https://legendapp.com/open-source/state/v3/",
"routes": [
{
"url": "/demo/legend-state",
"name": "Legend State"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@legendapp/state": "3.0.0-beta.30"
}
}