Created
February 22, 2025 09:26
-
-
Save nguyenyou/77607cb2ab7516d53b80a28a802d3e6e to your computer and use it in GitHub Desktop.
laminar-todoapp
This file contains hidden or 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
//> using scala 3.6.3 | |
//> using platform scala-js | |
//> using dep "org.scala-js::scalajs-dom::2.8.0" | |
//> using dep "com.raquo::laminar::17.2.0" | |
//> using jsModuleKind es | |
//> using jsModuleSplitStyleStr fewestmodules | |
package myapp | |
import org.scalajs.dom | |
import com.raquo.laminar.api.L.* | |
case class Todo(id: Int, text: String, completed: Boolean) | |
@main | |
def main(): Unit = { | |
val container = dom.document.getElementById("app") | |
// State management | |
val todosVar = Var(Vector.empty[Todo]) | |
val inputVar = Var("") | |
def addTodo(text: String): Unit = | |
if text.trim.nonEmpty then | |
val newTodo = Todo( | |
id = System.currentTimeMillis().toInt, | |
text = text.trim, | |
completed = false | |
) | |
todosVar.update(_ :+ newTodo) | |
inputVar.set("") | |
def toggleTodo(id: Int): Unit = | |
todosVar.update(_.map { todo => | |
if todo.id == id then todo.copy(completed = !todo.completed) | |
else todo | |
}) | |
def deleteTodo(id: Int): Unit = | |
todosVar.update(_.filterNot(_.id == id)) | |
render( | |
container, | |
div( | |
className := "max-w-md mx-auto mt-8 p-4", | |
// Input form | |
form( | |
className := "flex gap-2 mb-4", | |
onSubmit.preventDefault --> { _ => addTodo(inputVar.now()) }, | |
input( | |
className := "flex-1 px-4 py-2 border rounded focus:outline-none focus:border-blue-500", | |
placeholder := "Add a new todo...", | |
controlled( | |
value <-- inputVar, | |
onInput.mapToValue --> inputVar | |
) | |
), | |
button( | |
className := "px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600", | |
"Add" | |
) | |
), | |
// Todo list | |
div( | |
className := "space-y-2", | |
children <-- todosVar.signal.map { todos => | |
todos.map { todo => | |
div( | |
className := "flex items-center gap-2 p-2 border rounded", | |
input( | |
typ := "checkbox", | |
checked := todo.completed, | |
className := "h-5 w-5", | |
onClick --> { _ => toggleTodo(todo.id) } | |
), | |
span( | |
className := (if todo.completed then "line-through text-gray-500" else ""), | |
todo.text | |
), | |
button( | |
className := "ml-auto px-2 py-1 text-red-500 hover:bg-red-100 rounded", | |
onClick --> { _ => deleteTodo(todo.id) }, | |
"×" | |
) | |
) | |
} | |
} | |
) | |
) | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment