JSFiddle - React, Tailwind, and code Playground
by stefansarya
HTML
<link rel="stylesheet" href="https://unpkg.com/todomvc-app-css@2.2.0/index.css">
<script src="https://cdn.jsdelivr.net/npm/scarletsframe@0.32.11/dist/scarletsframe.min.js"></script>
<!-- Click "Run" before trying -->
<sf-m name="todos">
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input sf-bind="textInput"
@keyup="inputKeyUp"
class="new-todo"
placeholder="What needs to be done?"
autofocus
>
</header>
<section class="main">
<input class="toggle-all" type="checkbox">
<label @click="toggleAll" for="toggle-all">
Mark all as complete
</label>
<ul class="todo-list">
<li
sf-each="x in list"
class="{{ x.completed ? 'completed' : '' }}"
style="display: {{
(x.completed && switch === 'active' && 'none')
|| (!x.completed && switch === 'completed' && 'none')
|| 'block'
}}"
>
<div class="view">
<input @click="itemToggle(x)" sf-bind="x.completed" class="toggle" type="checkbox">
<label @click="clicking(x)">{{ x.value }}</label>
<button @pointerup="remove(x)" class="destroy"></button>
</div>
</li>
</ul>
</section>
<footer class="footer">
<span class="todo-count">
<strong>{{ itemsLeft }}</strong> items left
</span>
<ul class="filters">
<li>
<a @click="switch = 'all'"
class="{{ switch === 'all' ? 'selected' : '' }}">All</a>
</li>
<li>
<a @click="switch = 'active'"
class="{{ switch === 'active' ? 'selected' : '' }}">Active</a>
</li>
<li>
<a @click="switch = 'completed'"
class="{{ switch === 'completed' ? 'selected' : '' }}">Completed</a>
</li>
</ul>
<button @click="clearCompleted"
class="clear-completed"
style="display:...
CSS
a, input[type="checkbox"]{
cursor: pointer;
}
JavaScript
sf.model('todos', function(My){
// === Local Data ===
let modifyItem = null;
let modifyMode = null;
// === Reactivity ===
My.list = [/* {completed, value} */];
My.itemsLeft = 0;
My.switch = 'all';
My.textInput = '';
// === Local Storage ===
My.list = JSON.parse(localStorage.todos || '[]');
My.itemsLeft = My.list.length;
function saveList(){
localStorage.todos = JSON.stringify(My.list);
My.itemsLeft = My.list.filter((val)=> !val.completed).length;
}
// === Functions ===
My.inputKeyUp = function(e){
if(e.key === "Enter"){
if(!modifyMode){
My.list.push({
value: My.textInput,
completed: false
});
}
else modifyItem.value = My.textInput;
modifyItem = modifyMode = false;
My.textInput = '';
saveList();
}
}
My.itemToggle = function(item){
item.completed = !item.completed;
saveList();
}
let toggle = false;
My.toggleAll = function(){
toggle = !toggle;
My.list.forEach((x)=> {x.completed = toggle});
saveList();
}
My.clearCompleted = function(item){
My.list = My.list.filter((x)=> !x.completed);
saveList();
}
My.remove = function(item){
My.list.splice(My.list.indexOf(item), 1);
saveList();
}
My.clicking = function(item){
if(modifyItem === item){
My.textInput = item.value;
modifyMode = true;
My.$el('input.new-todo').focus();
return;
}
modifyItem = item;
modifyMode = false;
}
});