0.1.11 #14

Merged
Thilawyn merged 318 commits from next into master 2025-05-19 14:01:41 +02:00
3 changed files with 16 additions and 39 deletions
Showing only changes of commit b9e787f42b - Show all commits

View File

@@ -7,15 +7,8 @@ import { Chunk, Context, Effect, identity, Layer, ParseResult, Ref, Schema, Stre
export class TodosState extends Context.Tag("TodosState")<TodosState, { export class TodosState extends Context.Tag("TodosState")<TodosState, {
readonly todos: SubscriptionRef.SubscriptionRef<Chunk.Chunk<Todo.Todo>> readonly todos: SubscriptionRef.SubscriptionRef<Chunk.Chunk<Todo.Todo>>
readonly load: Effect.Effect<void, PlatformError | ParseResult.ParseError> readonly load: Effect.Effect<void, PlatformError | ParseResult.ParseError>
readonly save: Effect.Effect<void, PlatformError | ParseResult.ParseError> readonly save: Effect.Effect<void, PlatformError | ParseResult.ParseError>
readonly prepend: (todo: Todo.Todo) => Effect.Effect<void>
readonly replace: (index: number, todo: Todo.Todo) => Effect.Effect<void>
readonly remove: (index: number) => Effect.Effect<void>
// readonly moveUp: (index: number) => Effect.Effect<void, Cause.NoSuchElementException>
// readonly moveDown: (index: number) => Effect.Effect<void, Cause.NoSuchElementException>
}>() {} }>() {}
@@ -41,30 +34,11 @@ export const make = (key: string) => Layer.effect(TodosState, Effect.gen(functio
) )
const todos = yield* SubscriptionRef.make(yield* readFromLocalStorage) const todos = yield* SubscriptionRef.make(yield* readFromLocalStorage)
const load = Effect.flatMap(readFromLocalStorage, v => Ref.set(todos, v)) const load = Effect.flatMap(readFromLocalStorage, v => Ref.set(todos, v))
const save = Effect.flatMap(todos, writeToLocalStorage) const save = Effect.flatMap(todos, writeToLocalStorage)
const prepend = (todo: Todo.Todo) => Ref.update(todos, Chunk.prepend(todo))
const replace = (index: number, todo: Todo.Todo) => Ref.update(todos, Chunk.replace(index, todo))
const remove = (index: number) => Ref.update(todos, Chunk.remove(index))
// const moveUp = (index: number) => Effect.gen(function*() {
// })
// Sync changes with local storage // Sync changes with local storage
yield* Effect.forkScoped(todos.changes.pipe( yield* Effect.forkScoped(Stream.runForEach(todos.changes, writeToLocalStorage))
Stream.debounce("500 millis"),
Stream.runForEach(writeToLocalStorage),
))
return { return { todos, load, save }
todos,
load,
save,
prepend,
replace,
remove,
}
})) }))

View File

@@ -1,7 +1,7 @@
import { Todo } from "@/domain" import { Todo } from "@/domain"
import { Box, Button, Card, Flex, TextArea } from "@radix-ui/themes" import { Box, Button, Card, Flex, TextArea } from "@radix-ui/themes"
import { GetRandomValues, makeUuid4 } from "@typed/id" import { GetRandomValues, makeUuid4 } from "@typed/id"
import { Effect, Option, Ref } from "effect" import { Chunk, Effect, Option, Ref } from "effect"
import { R } from "../reffuse" import { R } from "../reffuse"
import { TodosState } from "../services" import { TodosState } from "../services"
@@ -18,7 +18,7 @@ export function VNewTodo() {
const [content, setContent] = R.useRefState(R.useSubRefFromPath(todoRef, ["content"])) const [content, setContent] = R.useRefState(R.useSubRefFromPath(todoRef, ["content"]))
const add = R.useCallbackSync(() => Effect.all([TodosState.TodosState, todoRef]).pipe( const add = R.useCallbackSync(() => Effect.all([TodosState.TodosState, todoRef]).pipe(
Effect.flatMap(([state, todo]) => state.prepend(todo)), Effect.flatMap(([state, todo]) => Ref.update(state.todos, Chunk.prepend(todo))),
Effect.andThen(createEmptyTodo), Effect.andThen(createEmptyTodo),
Effect.flatMap(v => Ref.set(todoRef, v)), Effect.flatMap(v => Ref.set(todoRef, v)),
), [todoRef]) ), [todoRef])

View File

@@ -1,6 +1,6 @@
import { Todo } from "@/domain" import { Todo } from "@/domain"
import { Box, Card, Flex, IconButton, TextArea } from "@radix-ui/themes" import { Box, Card, Flex, IconButton, TextArea } from "@radix-ui/themes"
import { Effect, Ref, SubscriptionRef } from "effect" import { Effect, Ref, Stream, SubscriptionRef } from "effect"
import { Delete } from "lucide-react" import { Delete } from "lucide-react"
import { useState } from "react" import { useState } from "react"
import { R } from "../reffuse" import { R } from "../reffuse"
@@ -14,7 +14,15 @@ export interface VTodoProps {
export function VTodo({ todoRef, remove }: VTodoProps) { export function VTodo({ todoRef, remove }: VTodoProps) {
const runSync = R.useRunSync() const runSync = R.useRunSync()
const [todo] = R.useSubscribeRefs(todoRef)
const localTodoRef = R.useRef(() => todoRef)
const [content, setContent] = R.useRefState(R.useSubRefFromPath(localTodoRef, ["content"]))
R.useFork(() => localTodoRef.changes.pipe(
Stream.debounce("250 millis"),
Stream.runForEach(v => Ref.set(todoRef, v)),
), [localTodoRef])
const editorMode = useState(false) const editorMode = useState(false)
@@ -23,13 +31,8 @@ export function VTodo({ todoRef, remove }: VTodoProps) {
<Card> <Card>
<Flex direction="column" align="stretch" gap="1"> <Flex direction="column" align="stretch" gap="1">
<TextArea <TextArea
value={todo.content} value={content}
onChange={e => runSync( onChange={e => setContent(e.target.value)}
Ref.set(todoRef, Todo.Todo.make({
...todo,
content: e.target.value,
}, true))
)}
disabled={!editorMode} disabled={!editorMode}
/> />