Skip to content

Commit

Permalink
improve todo-app example
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmood committed Sep 30, 2024
1 parent 25830ca commit a4f0eae
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 25 deletions.
19 changes: 14 additions & 5 deletions examples/TodoApp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
clearCompleted,
filters,
setFilter,
setTodosStatus,
useLeftCount,
} from "./store";

export default function TodoApp() {
Expand All @@ -18,6 +20,10 @@ export default function TodoApp() {
<div>
<h3>Todo App</h3>
<div>
<input
type="checkbox"
onChange={(e) => setTodosStatus(e.target.checked)}
/>
<Filter />
<button onClick={addTodo}>Add todo</button>
</div>
Expand All @@ -29,6 +35,7 @@ export default function TodoApp() {
})}
</div>

<span className="mr-5px">{useLeftCount()} todo left</span>
<button onClick={clearCompleted}>Clear completed</button>
</div>
);
Expand All @@ -50,7 +57,7 @@ function TodoItem({ id }: { id: number }) {
const { done, text, editing } = useTodo(id);

return (
<div>
<div className="my-5px">
<label>
<input type="checkbox" checked={done} onChange={() => toggleTodo(id)} />
</label>
Expand All @@ -59,8 +66,10 @@ function TodoItem({ id }: { id: number }) {
<TodoEditor id={id} text={text} />
) : (
<>
<input value={text} readOnly style={{ borderColor: "transparent" }} />
<button onClick={() => setTodoMode(id, true)}>Edit</button>
<input value={text} readOnly className="border-transparent" />
<button onClick={() => setTodoMode(id, true)} className="width-50px">
Edit
</button>
</>
)}

Expand All @@ -78,7 +87,7 @@ function TodoEditor({ id, text }: { id: number; text: string }) {

return (
<form
style={{ display: "inline" }}
className="inline"
onSubmit={(e) => {
e.preventDefault();
setTodoMode(id, false);
Expand All @@ -90,7 +99,7 @@ function TodoEditor({ id, text }: { id: number; text: string }) {
value={text}
onChange={(e) => updateTodo(id, e.target.value)}
/>
<input type="submit" value="Save" />
<input type="submit" value="Save" className="width-50px" />
</form>
);
}
53 changes: 35 additions & 18 deletions examples/TodoApp/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,16 @@ export function addTodo() {
export function useList() {
return useStore(
useEqual((s) => {
return s.todos
.filter((todo) => {
switch (s.filter) {
case "All":
return true;
case "Active":
return !todo.done;
case "Completed":
return todo.done;
}
})
.map((todo) => todo.id);
return filterTodos(s).map(({ id }) => id);
}, numbersEqual)
);
}

// Get the count of the left todos.
export function useLeftCount() {
return useStore((s) => s.todos.filter(({ done }) => !done).length);
}

// Get a todo by id.
export function useTodo(id: number) {
return useStore((s) => findTodo(s, id));
Expand All @@ -60,11 +54,6 @@ export function delTodo(id: number) {
}, true);
}

// Find a todo by id.
function findTodo(s: typeof initStore, id: number) {
return s.todos.find((todo) => todo.id === id)!;
}

// Toggle the done state of a todo by id.
export function toggleTodo(id: number) {
setStore((s) => {
Expand All @@ -75,6 +64,15 @@ export function toggleTodo(id: number) {
}, true);
}

// Toggle all the current filtered todos.
export function setTodosStatus(done: boolean) {
setStore((s) => {
filterTodos(s).forEach((todo) => {
todo.done = done;
});
}, true);
}

// Set the editing state of a todo by id.
export function setTodoMode(id: number, editing: boolean) {
setStore((s) => {
Expand All @@ -93,7 +91,7 @@ export function updateTodo(id: number, text: string) {
// Clear all completed todos.
export function clearCompleted() {
setStore((s) => {
s.todos = s.todos.filter((todo) => !todo.done);
s.todos = s.todos.filter(({ done }) => !done);
}, true);
}

Expand All @@ -104,6 +102,25 @@ export function setFilter(filter: string) {
});
}

// Find a todo by id.
function findTodo(s: typeof initStore, id: number) {
return s.todos.find((todo) => todo.id === id)!;
}

// Filter the todos by the current status.
function filterTodos(s: typeof initStore) {
return s.todos.filter(({ done }) => {
switch (s.filter) {
case "All":
return true;
case "Active":
return !done;
case "Completed":
return done;
}
});
}

// Compare two arrays' equality.
function numbersEqual<T>(x: T[], y: T[]) {
return x.length === y.length && x.every((v, i) => v === y[i]);
Expand Down
21 changes: 19 additions & 2 deletions examples/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
button, input, select {
margin: 5px;
.border-transparent {
border-color: transparent;
}

.my-5px {
margin-top: 5px;
margin-bottom: 5px;
}

.inline {
display: inline;
}

.width-50px {
width: 50px;
}

.mr-5px {
margin-right: 5px;
}

0 comments on commit a4f0eae

Please sign in to comment.