const {DOM} = Gale({ Button: { padding: "20px", background: "orange", ".Inner": { fontSize: "10rem" } }, Outline: { border: "2px solid orange" } }); /** @typedef {{done:boolean, text:string}} Todo */ /** @type {(obj:T, key:string)=>T} */ const Store =(obj, key)=> { const recall = localStorage.getItem(key); const store = vanX.reactive(recall ? JSON.parse(recall) : obj); van.derive(() => localStorage.setItem(key, JSON.stringify(vanX.compact(store)))); return store; } const items = Store({ pending:"", todos:/** @type {Todo[]}*/([]) }, "Todos?"); const {div, input, button, del, span, a} = van.tags; const TodoList = () => { const inputDom = input({type: "text", value:()=>items.pending, oninput(){items.pending = this.value}}); return div( ()=>div(items.pending), inputDom, DOM.button.Outline.Button({onclick: () => items.todos.push({text: inputDom.value, done: false})}, "Add"), vanX.list(div, items.todos, ({val: v}, deleter) => div( input({type: "checkbox", checked: () => v.done, onclick: e => v.done = e.target.checked}), () => (v.done ? del : span)(v.text), a({onclick: deleter}, "❌"), )), ) } van.add(document.body, TodoList());