Skip to content
Permalink
main
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
<!doctype html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
<style>
:root {
font-family: Roboto;
margin-top: 16px;
}
body {
padding: 8px;
margin: 8px auto;
max-width: 800px;
}
h1,h2,h3,h4,h5,h6 {
margin: 0;
}
.flex {
display: flex;
}
.items-center {
align-items: center;
}
.items-end {
align-items: flex-end;
}
.muted {
opacity: 0.5;
}
.btn {
background: gainsboro;
border: none;
border-bottom: 1px solid #1221;
border-radius: 4px;
cursor: pointer;
font-family: Roboto;
font-weight: 500;
padding: 0.5em 1em;
transition: filter 0.2s;
}
.btn:hover {
filter: brightness(85%) contrast(133%);
}
.btn.primary {
background: royalblue;
color: white;
}
.badge {
border-radius: 10px;
font-size: 11px;
font-weight: 500;
padding: 0.2em 0.8em;
background: #ccc;
}
.ml-4 {
margin-left: 4px;
}
.mr-4 {
margin-right: 4px;
}
</style>
</head>
<body>
<h1>Todo list</h1>
<todo-items></todo-items>
</body>
<script type="module">
import { El } from './el.js'
const store = El.observable({
items: [
{ id: key(), title: "buy milk" },
{ id: key(), title: "buy bread" },
{ id: key(), title: "buy eggs" },
],
})
class TodoItem extends El {
editItem() {
const title = window.prompt("Enter title", this.item.title)
if (title !== null) this.item.title = title
}
toggleDone() {
this.item.done = !this.item.done
}
deleteItem() {
const index = store.items.findIndex(i => i.id == this.item.id)
store.items.splice(index, 1)
}
render(html) {
return html`
<span class="status-column">
${this.item.done
? html`<span class="badge success">Done!</span>`
: html`<span class="badge">New</span>`
}
</span>
<span>
<input
type="checkbox"
${this.item.done && 'checked'}
onclick=${this.toggleDone}>
</span>
<span><p class="muted">${this.item.id}</p></span>
<span class="title-column ${this.item.done && 'title--completed'}">
<h3>${this.item.title}</h3>
</span>
<span class="tools-column">
<button class="btn" onclick=${this.editItem}>Edit</button>
<button class="btn delete muted" title="Delete item" onclick=${this.deleteItem}>&times;</button>
</span>
`
}
styles(css) {
return css`
:host {
display: table-row;
&(:hover) {
background-color: #8ff4;
}
> span {
display: table-cell;
padding: 0.5em;
border-bottom: 1px solid #2232;
}
}
.btn.delete {
background: transparent;
box-shadow: 0 0 0 1px #1234;
margin-left: 2px;
}
.btn.delete:hover {
background: crimson;
color: white;
box-shadow: none;
}
.badge.success {
background: mediumseagreen;
color: white;
}
.title-column {
width: 100%;
}
.status-column {
min-width: 3em;
}
.title--completed {
opacity: 0.5;
text-decoration: line-through;
}
.tools-column {
white-space: nowrap;
}
input[type=checkbox] {
position: relative;
top: 2px;
}
`
}
}
class TodoItems extends El {
addItem() {
const title = window.prompt("Enter title")
if (title === null) return
store.items.push({
id: key(),
title,
})
}
toggleHideCompleted(e) {
store.hideCompleted = e.target.checked
}
filteredItems() {
return store.items.filter(i => store.hideCompleted ? !i.done : true)
}
render(html) {
const items = this.filteredItems()
return html`
<div class="items-container">
<header class="flex items-center">
<h4 class="flex items-center">
Items
<span class="badge ml-4 mr-4">${items.length}</span>
</h4>
<label class="ml-4 flex items-end">
<input type="checkbox" onclick=${this.toggleHideCompleted}>
<small class="muted">Hide completed</small>
</label>
<button class="btn primary" onclick=${this.addItem}>Add item</button>
</header>
<div class="items">
${items.map(item => html`
<todo-item key="${item.id}" item=${item}></todo-item>
`)}
</div>
</div>
`
}
styles(css) {
return css`
.items-container {
display: table;
margin-top: 16px;
max-width: 600px;
width: 100%;
}
header {
background: whitesmoke;
box-shadow: 0 1px 1px #1232;
padding: 16px 8px;
> *:last-child {
margin-left: auto;
}
}
`
}
}
customElements.define('todo-item', TodoItem)
customElements.define('todo-items', TodoItems)
function key() {
return Math.random().toString(36).slice(2,8)
}
</script>