import type { IObjectOf } from "@thi.ng/api" ; import { defAtom } from "@thi.ng/atom/atom" ; import { defCursor } from "@thi.ng/atom/cursor" ; import { defHistory } from "@thi.ng/atom/history" ; import { defView } from "@thi.ng/atom/view" ; import { start } from "@thi.ng/hdom/start" ; import { map } from "@thi.ng/transducers/map" ; import { pairs } from "@thi.ng/transducers/pairs" ; interface Task { done : boolean ; body : string ; } type Tasks = IObjectOf < Task > ; interface State { tasks : Tasks ; nextID : number ; } const db = defAtom < State > ( { tasks : { } , nextID : 0 } ) ; const tasks = defHistory ( defCursor < State , "tasks" > ( db , [ "tasks" ] ) , 100 ) ; const nextID = defCursor ( db , [ "nextID" ] ) ; const items = defView ( db , [ "tasks" ] , ( tasks ) => [ ... map ( ( [ id , t ] ) => taskItem ( id , t ) , pairs ( tasks ) ) , ] ) ; const addNewTask = ( ) => tasks . resetIn ( [ nextID . swap ( ( id ) => id + 1 ) ] , { body : "" , done : false } ) ; const toggleTask = ( id ) => tasks . swapIn ( < const > [ id , "done" ] , ( done ) => ! done ) ; const updateTask = ( id , body ) => tasks . resetIn ( < const > [ id , "body" ] , body ) ; const taskItem = ( id , task ) : any [ ] => { const checkAttribs = { type : "checkbox" , checked : task . done , onclick : ( ) => toggleTask ( id ) , } ; const textAttribs = { type : "text" , placeholder : "todo..." , value : task . body , onkeydown : ( e ) => e . key === "Enter" && e . target . blur ( ) , onblur : ( e ) => updateTask ( id , ( < HTMLInputElement > e . target ) . value ) , } ; return [ "div" , { class : "task" + ( task . done ? " done" : "" ) } , [ "input" , checkAttribs ] , [ "input" , textAttribs ] , ] ; } ; const taskList = ( ) => { const _items = items . deref ( ) ! ; return _items . length ? [ "div#tasks" , _items ] : [ "div" , "nothing todo, get busy..." ] ; } ; const button = ( onclick , body ) => ( _ , disabled ) => [ "button" , { onclick , disabled } , body ] ; const toolbar = ( ) => { const btAdd = button ( ( ) => addNewTask ( ) , "+ Add" ) ; const btUndo = button ( ( ) => tasks . undo ( ) , "Undo" ) ; const btRedo = button ( ( ) => tasks . redo ( ) , "Redo" ) ; return ( ) => [ "div#toolbar" , [ btAdd ] , [ btUndo , ! tasks . canUndo ( ) ] , [ btRedo , ! tasks . canRedo ( ) ] , ] ; } ; const header = [ "h1" , "My tasks" , [ "small" , "made with \u2764 " , [ "a" , { href : "https://github.com/thi-ng/umbrella/tree/develop/packages/hdom" , } , "@thi.ng/hdom" , ] , ] , ] ; const app = ( ) => { return [ "div" , header , toolbar ( ) , taskList ] ; } ; start ( app ( ) ) ;