Created
March 23, 2020 00:18
-
-
Save samholmes/d66360731dc4b4205241f6c185813c6d to your computer and use it in GitHub Desktop.
IronJS TodoMVC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en" data-framework="ironjs"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<title>IronJS • TodoMVC</title> | |
<link rel="stylesheet" href="https://unpkg.com/todomvc-common/base.css" /> | |
<link rel="stylesheet" href="https://unpkg.com/todomvc-app-css/index.css" /> | |
</head> | |
<body> | |
<script src="https://unpkg.com/todomvc-common/base.js"></script> | |
<script type="module" src="iron-todomvc.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import plur from 'https://cdn.pika.dev/plur'; | |
import { e, v, jarvis } from 'https://unpkg.com/ironjs@0.0.22-alpha'; | |
// init store | |
// State | |
// Debugging toggle for mutation API | |
const useMutationAPI = true; | |
// Hash | |
const hashchangeEvent = v.fromEvent(window, 'hashchange'); | |
const hash = v(() => (hashchangeEvent.v, window.location.hash || '#all')); | |
// Items | |
const items = v([]); | |
// How many items remain | |
const remains = v(() => items.v.filter(item => !item.v.done).length); | |
// Debugging Logs | |
// console.log(items); | |
// v.log(items); | |
// App entry | |
const App = () => | |
e.section.todoapp( | |
e.header.header( | |
e.h1('todos'), | |
e.input['new-todo']({ | |
placeholder: 'What needs to be done?', | |
autofocus: true, | |
keypress: newTodoKeypressHandler, | |
}) | |
), | |
e.section.main( | |
e.input['#toggle-all.toggle-all']({ | |
type: 'checkbox', | |
click: toggleAll, | |
}), | |
e.label({ for: 'toggle-all' }, 'Mark all as complete'), | |
ListElements | |
), | |
e.footer.footer( | |
{ hidden: v(() => !items.v.length) }, | |
TodoCount, | |
e.ul.filters( | |
Filter({ tag: '#all' }, 'All'), | |
Filter({ tag: '#active' }, 'Active'), | |
Filter({ tag: '#completed' }, 'Completed') | |
), | |
e.button['clear-completed']('Clear completed', { | |
click: clearCompleted, | |
hidden: v(() => !items.v.some(item => item.v.done)), | |
}) | |
) | |
); | |
// Elements | |
const ListElements = e.ul['todo-list']( | |
v(() => | |
items.map((item, index) => | |
Item({ item, onRemove: () => removeItem(index) }) | |
) | |
) | |
); | |
const Item = ({ item, onRemove }) => { | |
const editRef = v(); | |
const editing = v(false); | |
const hidden = v( | |
() => | |
hash.v !== '#all' && | |
((hash.v === '#active' && item.v.done) || | |
(hash.v === '#completed' && !item.v.done)) | |
); | |
const classes = v(() => [ | |
item.v.done ? 'completed' : '', | |
editing.v ? 'editing' : '', | |
]); | |
const startEditing = () => ((editing.v = true), editRef.v.focus()); | |
const stopEditing = () => (editing.v = false); | |
return e.li( | |
{ classes, hidden }, | |
e.div.view( | |
e.input.toggle({ | |
type: 'checkbox', | |
checked: v(() => item.v.done), | |
click: () => (item.v = { ...item.v, done: !item.v.done }), | |
}), | |
e.label({ dblclick: startEditing }, item.v.text), | |
e.button.destroy({ click: onRemove }) | |
), | |
e.input.edit({ | |
value: item.v.text, | |
ref: editRef, | |
change: ev => (item.v = { ...item.v, text: ev.target.value }), | |
blur: stopEditing, | |
keypress: ev => ev.key === 'Enter' && ev.target.blur(), | |
}) | |
); | |
}; | |
const Filter = e(({ tag }, children) => | |
e.li( | |
e.a( | |
{ | |
href: tag, | |
classes: v(() => (hash.v === tag ? ['selected'] : [])), | |
}, | |
children | |
) | |
) | |
); | |
const TodoCount = e.span['todo-count']( | |
v(() => [e.strong(remains.v), plur(' item', remains.v), ' left']) | |
); | |
// Events | |
function newTodoKeypressHandler(ev) { | |
if (ev.key === 'Enter') { | |
const text = ev.target.value; | |
ev.target.value = ''; | |
const item = v({ text, done: false }); | |
if (useMutationAPI) items.push(item); | |
else items.v = items.v.concat(item); | |
} | |
} | |
function clearCompleted() { | |
if (useMutationAPI) { | |
let count = 0; | |
items.v | |
.map(item => item) | |
.forEach(({ v: { done } }, index) => { | |
if (done) { | |
items.pull(index - count); | |
count += 1; | |
} | |
}); | |
} else { | |
items.v = items.v.filter(item => !item.v.done); | |
} | |
} | |
function removeItem(index) { | |
if (useMutationAPI) { | |
items.pull(index); | |
} else { | |
items.v = items.v.filter((item, i) => index !== i); | |
} | |
} | |
function toggleAll() { | |
const done = !items.v.every(item => item.v.done); | |
items.v.forEach(item => { | |
if (item.v.done !== done) item.v = { ...item.v, done }; | |
}); | |
} | |
// Render | |
jarvis.render(App(), document.body); | |
// Local Storage | |
// Get localStorageData | |
let localStorageData = localStorage.getItem('todomvc.items'); | |
// Retrieve | |
items.v = localStorageData | |
? JSON.parse(localStorageData).map(item => v(item)) | |
: []; | |
// Store | |
v(() => | |
localStorage.setItem( | |
'todomvc.items', | |
JSON.stringify(items.v.map(item => item.v)) | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment